{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e913cef7-f00f-46a5-8b17-2192bc382b64",
   "metadata": {},
   "outputs": [],
   "source": [
    "智能问答机器人 v0.6：和业务的 API 打通\n",
    "\n",
    "上线之后，用户反馈不错。但又有新需求了，程序员，总有干不完的需求。\n",
    "\n",
    "产品经理说，用户很多问题都和业务数据有关，咱们机器人是不是能和业务的 API 打通？比如，是不是能和我们的订单系统打通？这样小墨的能力就更强了。\n",
    "\n",
    "相关技术点：\n",
    "\n",
    "LangChain（自主决策能力的 Agent & 让一切变成现实的 Tools & 抽象业务调用的 Chain）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "910fefa3-7b2c-49ee-a403-67d4ae9c37f1",
   "metadata": {},
   "outputs": [],
   "source": [
    "知识库来源\n",
    "https://macshuo.com/"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7cec982-4c70-4ed6-94b3-3046070eca32",
   "metadata": {},
   "source": [
    "# 本节大纲\n",
    "1. 版本介绍, 10分钟\n",
    "2. LangChain Memory, 20分钟\n",
    "3. LangChain Chains, 20分钟\n",
    "4. LangChain Expression Language, 10分钟\n",
    "5. LangChain Agent, 30分钟\n",
    "6. 工程化代码开发，20分钟\n",
    "7. 答疑和总结，10分钟"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f00bd50-556d-4830-b69e-fd35822e8f8c",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a61c41c9-3442-4a65-bfe8-1abe7285f986",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "23c92bb6-07a0-4aef-88e1-e35a3770ec6b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "64a39843-890e-41ea-9e2e-2df882c7b6b7",
   "metadata": {},
   "source": [
    "## 小墨 v0.6 介绍"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba34eec1-526e-4814-8db7-50d4e60f5531",
   "metadata": {},
   "source": [
    "![v0.6](./resource/images/v0.6.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3e6c837-d6a9-40ff-9686-cbb9c7be3856",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 还记得向量空间吗，或者是维度空间？\n",
    "# 如果我们把小墨也在更高维度进行抽象，那会变成什么？\n",
    "# 原先对于知识库是否就是一个工具/能力的抽象而已\n",
    "# 那小墨就可以掌握更多的技能了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "90469330-90ba-466c-9ff6-76acfb038992",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dc83f611-abe1-4883-851b-fcf14573ef7f",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f40feaf7-ff8d-479a-8fc8-dae83455d734",
   "metadata": {},
   "outputs": [],
   "source": [
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "765d70a4-6e6f-4344-94b7-a8014f59c067",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: openai in /opt/conda/lib/python3.11/site-packages (0.28.1)\n",
      "Requirement already satisfied: langchain in /opt/conda/lib/python3.11/site-packages (0.0.321)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.11/site-packages (3.2)\n",
      "Requirement already satisfied: faiss-cpu in /opt/conda/lib/python3.11/site-packages (1.7.4)\n",
      "Requirement already satisfied: numexpr in /opt/conda/lib/python3.11/site-packages (2.8.7)\n",
      "Requirement already satisfied: langchainhub in /opt/conda/lib/python3.11/site-packages (0.1.13)\n",
      "Requirement already satisfied: chromadb in /opt/conda/lib/python3.11/site-packages (0.4.15)\n",
      "Requirement already satisfied: langchain_experimental in /opt/conda/lib/python3.11/site-packages (0.0.36)\n",
      "Requirement already satisfied: pymysql in /opt/conda/lib/python3.11/site-packages (1.1.0)\n",
      "Requirement already satisfied: requests>=2.20 in /opt/conda/lib/python3.11/site-packages (from openai) (2.31.0)\n",
      "Requirement already satisfied: tqdm in /opt/conda/lib/python3.11/site-packages (from openai) (4.66.1)\n",
      "Requirement already satisfied: aiohttp in /opt/conda/lib/python3.11/site-packages (from openai) (3.8.6)\n",
      "Requirement already satisfied: PyYAML>=5.3 in /opt/conda/lib/python3.11/site-packages (from langchain) (6.0.1)\n",
      "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /opt/conda/lib/python3.11/site-packages (from langchain) (2.0.20)\n",
      "Requirement already satisfied: anyio<4.0 in /opt/conda/lib/python3.11/site-packages (from langchain) (3.7.1)\n",
      "Requirement already satisfied: dataclasses-json<0.7,>=0.5.7 in /opt/conda/lib/python3.11/site-packages (from langchain) (0.6.1)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /opt/conda/lib/python3.11/site-packages (from langchain) (1.33)\n",
      "Requirement already satisfied: langsmith<0.1.0,>=0.0.43 in /opt/conda/lib/python3.11/site-packages (from langchain) (0.0.49)\n",
      "Requirement already satisfied: numpy<2,>=1 in /opt/conda/lib/python3.11/site-packages (from langchain) (1.26.1)\n",
      "Requirement already satisfied: pydantic<3,>=1 in /opt/conda/lib/python3.11/site-packages (from langchain) (2.4.2)\n",
      "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /opt/conda/lib/python3.11/site-packages (from langchain) (8.2.3)\n",
      "Requirement already satisfied: types-requests<3.0.0.0,>=2.31.0.2 in /opt/conda/lib/python3.11/site-packages (from langchainhub) (2.31.0.6)\n",
      "Requirement already satisfied: chroma-hnswlib==0.7.3 in /opt/conda/lib/python3.11/site-packages (from chromadb) (0.7.3)\n",
      "Requirement already satisfied: fastapi>=0.95.2 in /opt/conda/lib/python3.11/site-packages (from chromadb) (0.104.0)\n",
      "Requirement already satisfied: uvicorn[standard]>=0.18.3 in /opt/conda/lib/python3.11/site-packages (from chromadb) (0.23.2)\n",
      "Requirement already satisfied: posthog>=2.4.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (3.0.2)\n",
      "Requirement already satisfied: typing-extensions>=4.5.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (4.8.0)\n",
      "Requirement already satisfied: pulsar-client>=3.1.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (3.3.0)\n",
      "Requirement already satisfied: onnxruntime>=1.14.1 in /opt/conda/lib/python3.11/site-packages (from chromadb) (1.16.1)\n",
      "Requirement already satisfied: opentelemetry-api>=1.2.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (1.20.0)\n",
      "Requirement already satisfied: opentelemetry-exporter-otlp-proto-grpc>=1.2.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (1.20.0)\n",
      "Requirement already satisfied: opentelemetry-sdk>=1.2.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (1.20.0)\n",
      "Requirement already satisfied: tokenizers>=0.13.2 in /opt/conda/lib/python3.11/site-packages (from chromadb) (0.14.1)\n",
      "Requirement already satisfied: pypika>=0.48.9 in /opt/conda/lib/python3.11/site-packages (from chromadb) (0.48.9)\n",
      "Requirement already satisfied: overrides>=7.3.1 in /opt/conda/lib/python3.11/site-packages (from chromadb) (7.4.0)\n",
      "Requirement already satisfied: importlib-resources in /opt/conda/lib/python3.11/site-packages (from chromadb) (6.0.1)\n",
      "Requirement already satisfied: grpcio>=1.58.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (1.59.0)\n",
      "Requirement already satisfied: bcrypt>=4.0.1 in /opt/conda/lib/python3.11/site-packages (from chromadb) (4.0.1)\n",
      "Requirement already satisfied: typer>=0.9.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (0.9.0)\n",
      "Requirement already satisfied: kubernetes>=28.1.0 in /opt/conda/lib/python3.11/site-packages (from chromadb) (28.1.0)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /opt/conda/lib/python3.11/site-packages (from aiohttp->openai) (23.1.0)\n",
      "Requirement already satisfied: charset-normalizer<4.0,>=2.0 in /opt/conda/lib/python3.11/site-packages (from aiohttp->openai) (3.2.0)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /opt/conda/lib/python3.11/site-packages (from aiohttp->openai) (6.0.4)\n",
      "Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /opt/conda/lib/python3.11/site-packages (from aiohttp->openai) (4.0.3)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /opt/conda/lib/python3.11/site-packages (from aiohttp->openai) (1.9.2)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /opt/conda/lib/python3.11/site-packages (from aiohttp->openai) (1.4.0)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /opt/conda/lib/python3.11/site-packages (from aiohttp->openai) (1.3.1)\n",
      "Requirement already satisfied: idna>=2.8 in /opt/conda/lib/python3.11/site-packages (from anyio<4.0->langchain) (3.4)\n",
      "Requirement already satisfied: sniffio>=1.1 in /opt/conda/lib/python3.11/site-packages (from anyio<4.0->langchain) (1.3.0)\n",
      "Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in /opt/conda/lib/python3.11/site-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (3.20.1)\n",
      "Requirement already satisfied: typing-inspect<1,>=0.4.0 in /opt/conda/lib/python3.11/site-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (0.9.0)\n",
      "Requirement already satisfied: starlette<0.28.0,>=0.27.0 in /opt/conda/lib/python3.11/site-packages (from fastapi>=0.95.2->chromadb) (0.27.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in /opt/conda/lib/python3.11/site-packages (from jsonpatch<2.0,>=1.33->langchain) (2.0)\n",
      "Requirement already satisfied: certifi>=14.05.14 in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (2023.7.22)\n",
      "Requirement already satisfied: six>=1.9.0 in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (1.16.0)\n",
      "Requirement already satisfied: python-dateutil>=2.5.3 in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (2.8.2)\n",
      "Requirement already satisfied: google-auth>=1.0.1 in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (2.23.3)\n",
      "Requirement already satisfied: websocket-client!=0.40.0,!=0.41.*,!=0.42.*,>=0.32.0 in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (1.6.2)\n",
      "Requirement already satisfied: requests-oauthlib in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (1.3.1)\n",
      "Requirement already satisfied: oauthlib>=3.2.2 in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (3.2.2)\n",
      "Requirement already satisfied: urllib3<2.0,>=1.24.2 in /opt/conda/lib/python3.11/site-packages (from kubernetes>=28.1.0->chromadb) (1.26.18)\n",
      "Requirement already satisfied: coloredlogs in /opt/conda/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (15.0.1)\n",
      "Requirement already satisfied: flatbuffers in /opt/conda/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (23.5.26)\n",
      "Requirement already satisfied: packaging in /opt/conda/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (23.1)\n",
      "Requirement already satisfied: protobuf in /opt/conda/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (4.24.4)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (1.12)\n",
      "Requirement already satisfied: deprecated>=1.2.6 in /opt/conda/lib/python3.11/site-packages (from opentelemetry-api>=1.2.0->chromadb) (1.2.14)\n",
      "Requirement already satisfied: importlib-metadata<7.0,>=6.0 in /opt/conda/lib/python3.11/site-packages (from opentelemetry-api>=1.2.0->chromadb) (6.8.0)\n",
      "Requirement already satisfied: backoff<3.0.0,>=1.10.0 in /opt/conda/lib/python3.11/site-packages (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb) (2.2.1)\n",
      "Requirement already satisfied: googleapis-common-protos~=1.52 in /opt/conda/lib/python3.11/site-packages (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb) (1.61.0)\n",
      "Requirement already satisfied: opentelemetry-exporter-otlp-proto-common==1.20.0 in /opt/conda/lib/python3.11/site-packages (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb) (1.20.0)\n",
      "Requirement already satisfied: opentelemetry-proto==1.20.0 in /opt/conda/lib/python3.11/site-packages (from opentelemetry-exporter-otlp-proto-grpc>=1.2.0->chromadb) (1.20.0)\n",
      "Requirement already satisfied: opentelemetry-semantic-conventions==0.41b0 in /opt/conda/lib/python3.11/site-packages (from opentelemetry-sdk>=1.2.0->chromadb) (0.41b0)\n",
      "Requirement already satisfied: monotonic>=1.5 in /opt/conda/lib/python3.11/site-packages (from posthog>=2.4.0->chromadb) (1.6)\n",
      "Requirement already satisfied: annotated-types>=0.4.0 in /opt/conda/lib/python3.11/site-packages (from pydantic<3,>=1->langchain) (0.6.0)\n",
      "Requirement already satisfied: pydantic-core==2.10.1 in /opt/conda/lib/python3.11/site-packages (from pydantic<3,>=1->langchain) (2.10.1)\n",
      "Requirement already satisfied: greenlet!=0.4.17 in /opt/conda/lib/python3.11/site-packages (from SQLAlchemy<3,>=1.4->langchain) (2.0.2)\n",
      "Requirement already satisfied: huggingface_hub<0.18,>=0.16.4 in /opt/conda/lib/python3.11/site-packages (from tokenizers>=0.13.2->chromadb) (0.17.3)\n",
      "Requirement already satisfied: click<9.0.0,>=7.1.1 in /opt/conda/lib/python3.11/site-packages (from typer>=0.9.0->chromadb) (8.1.7)\n",
      "Requirement already satisfied: types-urllib3 in /opt/conda/lib/python3.11/site-packages (from types-requests<3.0.0.0,>=2.31.0.2->langchainhub) (1.26.25.14)\n",
      "Requirement already satisfied: h11>=0.8 in /opt/conda/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.14.0)\n",
      "Requirement already satisfied: httptools>=0.5.0 in /opt/conda/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.6.1)\n",
      "Requirement already satisfied: python-dotenv>=0.13 in /opt/conda/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (1.0.0)\n",
      "Requirement already satisfied: uvloop!=0.15.0,!=0.15.1,>=0.14.0 in /opt/conda/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.19.0)\n",
      "Requirement already satisfied: watchfiles>=0.13 in /opt/conda/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.21.0)\n",
      "Requirement already satisfied: websockets>=10.4 in /opt/conda/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (12.0)\n",
      "Requirement already satisfied: wrapt<2,>=1.10 in /opt/conda/lib/python3.11/site-packages (from deprecated>=1.2.6->opentelemetry-api>=1.2.0->chromadb) (1.15.0)\n",
      "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /opt/conda/lib/python3.11/site-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb) (5.3.2)\n",
      "Requirement already satisfied: pyasn1-modules>=0.2.1 in /opt/conda/lib/python3.11/site-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb) (0.3.0)\n",
      "Requirement already satisfied: rsa<5,>=3.1.4 in /opt/conda/lib/python3.11/site-packages (from google-auth>=1.0.1->kubernetes>=28.1.0->chromadb) (4.9)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.11/site-packages (from huggingface_hub<0.18,>=0.16.4->tokenizers>=0.13.2->chromadb) (3.13.0)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.11/site-packages (from huggingface_hub<0.18,>=0.16.4->tokenizers>=0.13.2->chromadb) (2023.10.0)\n",
      "Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.11/site-packages (from importlib-metadata<7.0,>=6.0->opentelemetry-api>=1.2.0->chromadb) (3.16.2)\n",
      "Requirement already satisfied: mypy-extensions>=0.3.0 in /opt/conda/lib/python3.11/site-packages (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain) (1.0.0)\n",
      "Requirement already satisfied: humanfriendly>=9.1 in /opt/conda/lib/python3.11/site-packages (from coloredlogs->onnxruntime>=1.14.1->chromadb) (10.0)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.11/site-packages (from sympy->onnxruntime>=1.14.1->chromadb) (1.3.0)\n",
      "Requirement already satisfied: pyasn1<0.6.0,>=0.4.6 in /opt/conda/lib/python3.11/site-packages (from pyasn1-modules>=0.2.1->google-auth>=1.0.1->kubernetes>=28.1.0->chromadb) (0.5.0)\n"
     ]
    }
   ],
   "source": [
    "!pip install openai langchain networkx faiss-cpu numexpr langchainhub chromadb langchain_experimental pymysql"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9dbe112d-1733-4b15-a776-140c6dcf8ac4",
   "metadata": {},
   "source": [
    "## LangChain App Architecture"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "985fa00b-db68-4803-935f-b77cbb5535f6",
   "metadata": {},
   "source": [
    "![Production-Oriented_LangChain](./resource/images/Production-Oriented_LangChain.jpeg)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a77f914b-827c-4dad-a579-320cf3b7d0df",
   "metadata": {},
   "source": [
    "### Memory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7e3ac675-a3b3-4aff-936b-4899f4ba87b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在第一节课，我们是依赖 Gradio 每次对话时都把历史消息进行传递\n",
    "# 但 LLM 的 Token 是有限制，如何对 记忆力 进行控制呢"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "09594180-7a17-4be1-a919-6d2cdef65e93",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "fb412894-0ef3-4e4c-bb07-8f9588785e4b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'赵雷是一位才华横溢的歌手，以其深情的歌曲和独特的嗓音赢得了众多粉丝的喜爱。'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.schema import AIMessage, HumanMessage, SystemMessage\n",
    "\n",
    "messages = [\n",
    "    SystemMessage(content=\"你是一个有用的助手\"),\n",
    "    HumanMessage(content=\"用20个字介绍下歌手赵雷\"),\n",
    "]\n",
    "\n",
    "llm(messages).content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c4349b78-3b4a-49f2-aecc-c216cecb4db6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'您刚刚问我什么了？'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "messages = [\n",
    "    HumanMessage(content=\"我刚问你什么了？\"),\n",
    "]\n",
    "\n",
    "llm(messages).content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "68bdc575-dd70-4d2a-b9d4-a3db4dc8a8bb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'您刚刚问我如何用20个字介绍歌手赵雷。'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# LLM 本身是没有记忆的，LLM的记忆是需要我们自行处理的\n",
    "messages = [\n",
    "    SystemMessage(content=\"你是一个有用的助手\"),\n",
    "    HumanMessage(content=\"用20个字介绍下歌手赵雷\"),\n",
    "    AIMessage(content=\"赵雷是一位才华横溢的歌手，以其深情的歌曲和独特的嗓音赢得了众多粉丝的喜爱。\"),\n",
    "    HumanMessage(content=\"我刚问你什么了？\"),\n",
    "]\n",
    "\n",
    "llm(messages).content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "fd2ce021-e283-43ca-931b-ff34d7200f7b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AIMessage(content='您刚问我要用20个字介绍下歌手赵雷。')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 实际也可以用轻量级包装器的 ChatMessageHistory 类来处理\n",
    "from langchain.memory import ChatMessageHistory\n",
    "\n",
    "history = ChatMessageHistory()\n",
    "history.add_user_message(\"用20个字介绍下歌手赵雷\")\n",
    "history.add_ai_message(\"赵雷是一位才华横溢的歌手，以其深情的歌曲和独特的嗓音赢得了众多粉丝的喜爱\")\n",
    "history.add_user_message(\"我刚问你什么了？\")\n",
    "\n",
    "llm(history.messages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "9d13c8ac-b04d-401a-bbf6-af092121c4f5",
   "metadata": {},
   "outputs": [
    {
     "ename": "InvalidRequestError",
     "evalue": "This model's maximum context length is 4097 tokens. However, you requested 4111 tokens (21 in the messages, 4090 in the completion). Please reduce the length of the messages or completion.",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mInvalidRequestError\u001b[0m                       Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[9], line 11\u001b[0m\n\u001b[1;32m      2\u001b[0m llm \u001b[38;5;241m=\u001b[39m ChatOpenAI(\n\u001b[1;32m      3\u001b[0m     model_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mgpt-3.5-turbo-0613\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m      4\u001b[0m     temperature\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m, max_tokens\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m4090\u001b[39m,\n\u001b[1;32m      5\u001b[0m )\n\u001b[1;32m      7\u001b[0m messages \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m      8\u001b[0m     HumanMessage(content\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m用20个字介绍下歌手赵雷\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m      9\u001b[0m ]\n\u001b[0;32m---> 11\u001b[0m \u001b[43mllm\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mcontent\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/langchain/chat_models/base.py:600\u001b[0m, in \u001b[0;36mBaseChatModel.__call__\u001b[0;34m(self, messages, stop, callbacks, **kwargs)\u001b[0m\n\u001b[1;32m    593\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\n\u001b[1;32m    594\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m    595\u001b[0m     messages: List[BaseMessage],\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    598\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[1;32m    599\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m BaseMessage:\n\u001b[0;32m--> 600\u001b[0m     generation \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgenerate\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    601\u001b[0m \u001b[43m        \u001b[49m\u001b[43m[\u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcallbacks\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m    602\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mgenerations[\u001b[38;5;241m0\u001b[39m][\u001b[38;5;241m0\u001b[39m]\n\u001b[1;32m    603\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(generation, ChatGeneration):\n\u001b[1;32m    604\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m generation\u001b[38;5;241m.\u001b[39mmessage\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/langchain/chat_models/base.py:349\u001b[0m, in \u001b[0;36mBaseChatModel.generate\u001b[0;34m(self, messages, stop, callbacks, tags, metadata, run_name, **kwargs)\u001b[0m\n\u001b[1;32m    347\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m run_managers:\n\u001b[1;32m    348\u001b[0m             run_managers[i]\u001b[38;5;241m.\u001b[39mon_llm_error(e)\n\u001b[0;32m--> 349\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m e\n\u001b[1;32m    350\u001b[0m flattened_outputs \u001b[38;5;241m=\u001b[39m [\n\u001b[1;32m    351\u001b[0m     LLMResult(generations\u001b[38;5;241m=\u001b[39m[res\u001b[38;5;241m.\u001b[39mgenerations], llm_output\u001b[38;5;241m=\u001b[39mres\u001b[38;5;241m.\u001b[39mllm_output)\n\u001b[1;32m    352\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m res \u001b[38;5;129;01min\u001b[39;00m results\n\u001b[1;32m    353\u001b[0m ]\n\u001b[1;32m    354\u001b[0m llm_output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_combine_llm_outputs([res\u001b[38;5;241m.\u001b[39mllm_output \u001b[38;5;28;01mfor\u001b[39;00m res \u001b[38;5;129;01min\u001b[39;00m results])\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/langchain/chat_models/base.py:339\u001b[0m, in \u001b[0;36mBaseChatModel.generate\u001b[0;34m(self, messages, stop, callbacks, tags, metadata, run_name, **kwargs)\u001b[0m\n\u001b[1;32m    336\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(messages):\n\u001b[1;32m    337\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m    338\u001b[0m         results\u001b[38;5;241m.\u001b[39mappend(\n\u001b[0;32m--> 339\u001b[0m             \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_generate_with_cache\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    340\u001b[0m \u001b[43m                \u001b[49m\u001b[43mm\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    341\u001b[0m \u001b[43m                \u001b[49m\u001b[43mstop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    342\u001b[0m \u001b[43m                \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_managers\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mrun_managers\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m    343\u001b[0m \u001b[43m                \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    344\u001b[0m \u001b[43m            \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    345\u001b[0m         )\n\u001b[1;32m    346\u001b[0m     \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m    347\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m run_managers:\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/langchain/chat_models/base.py:492\u001b[0m, in \u001b[0;36mBaseChatModel._generate_with_cache\u001b[0;34m(self, messages, stop, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m    488\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m    489\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAsked to cache, but no cache found at `langchain.cache`.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m    490\u001b[0m     )\n\u001b[1;32m    491\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m new_arg_supported:\n\u001b[0;32m--> 492\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_generate\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    493\u001b[0m \u001b[43m        \u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstop\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstop\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m    494\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    495\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    496\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_generate(messages, stop\u001b[38;5;241m=\u001b[39mstop, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/langchain/chat_models/openai.py:360\u001b[0m, in \u001b[0;36mChatOpenAI._generate\u001b[0;34m(self, messages, stop, run_manager, stream, **kwargs)\u001b[0m\n\u001b[1;32m    358\u001b[0m message_dicts, params \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_create_message_dicts(messages, stop)\n\u001b[1;32m    359\u001b[0m params \u001b[38;5;241m=\u001b[39m {\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mparams, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs}\n\u001b[0;32m--> 360\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcompletion_with_retry\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    361\u001b[0m \u001b[43m    \u001b[49m\u001b[43mmessages\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmessage_dicts\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mparams\u001b[49m\n\u001b[1;32m    362\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    363\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_create_chat_result(response)\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/langchain/chat_models/openai.py:299\u001b[0m, in \u001b[0;36mChatOpenAI.completion_with_retry\u001b[0;34m(self, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m    295\u001b[0m \u001b[38;5;129m@retry_decorator\u001b[39m\n\u001b[1;32m    296\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_completion_with_retry\u001b[39m(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Any:\n\u001b[1;32m    297\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mclient\u001b[38;5;241m.\u001b[39mcreate(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m--> 299\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_completion_with_retry\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/tenacity/__init__.py:289\u001b[0m, in \u001b[0;36mBaseRetrying.wraps.<locals>.wrapped_f\u001b[0;34m(*args, **kw)\u001b[0m\n\u001b[1;32m    287\u001b[0m \u001b[38;5;129m@functools\u001b[39m\u001b[38;5;241m.\u001b[39mwraps(f)\n\u001b[1;32m    288\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mwrapped_f\u001b[39m(\u001b[38;5;241m*\u001b[39margs: t\u001b[38;5;241m.\u001b[39mAny, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkw: t\u001b[38;5;241m.\u001b[39mAny) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m t\u001b[38;5;241m.\u001b[39mAny:\n\u001b[0;32m--> 289\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mf\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkw\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/tenacity/__init__.py:379\u001b[0m, in \u001b[0;36mRetrying.__call__\u001b[0;34m(self, fn, *args, **kwargs)\u001b[0m\n\u001b[1;32m    377\u001b[0m retry_state \u001b[38;5;241m=\u001b[39m RetryCallState(retry_object\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m, fn\u001b[38;5;241m=\u001b[39mfn, args\u001b[38;5;241m=\u001b[39margs, kwargs\u001b[38;5;241m=\u001b[39mkwargs)\n\u001b[1;32m    378\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[0;32m--> 379\u001b[0m     do \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43miter\u001b[49m\u001b[43m(\u001b[49m\u001b[43mretry_state\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mretry_state\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    380\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(do, DoAttempt):\n\u001b[1;32m    381\u001b[0m         \u001b[38;5;28;01mtry\u001b[39;00m:\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/tenacity/__init__.py:314\u001b[0m, in \u001b[0;36mBaseRetrying.iter\u001b[0;34m(self, retry_state)\u001b[0m\n\u001b[1;32m    312\u001b[0m is_explicit_retry \u001b[38;5;241m=\u001b[39m fut\u001b[38;5;241m.\u001b[39mfailed \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(fut\u001b[38;5;241m.\u001b[39mexception(), TryAgain)\n\u001b[1;32m    313\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (is_explicit_retry \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mretry(retry_state)):\n\u001b[0;32m--> 314\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfut\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mresult\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    316\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mafter \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m    317\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mafter(retry_state)\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/concurrent/futures/_base.py:449\u001b[0m, in \u001b[0;36mFuture.result\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m    447\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m CancelledError()\n\u001b[1;32m    448\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_state \u001b[38;5;241m==\u001b[39m FINISHED:\n\u001b[0;32m--> 449\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__get_result\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    451\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_condition\u001b[38;5;241m.\u001b[39mwait(timeout)\n\u001b[1;32m    453\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_state \u001b[38;5;129;01min\u001b[39;00m [CANCELLED, CANCELLED_AND_NOTIFIED]:\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/concurrent/futures/_base.py:401\u001b[0m, in \u001b[0;36mFuture.__get_result\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    399\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception:\n\u001b[1;32m    400\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 401\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exception\n\u001b[1;32m    402\u001b[0m     \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m    403\u001b[0m         \u001b[38;5;66;03m# Break a reference cycle with the exception in self._exception\u001b[39;00m\n\u001b[1;32m    404\u001b[0m         \u001b[38;5;28mself\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/tenacity/__init__.py:382\u001b[0m, in \u001b[0;36mRetrying.__call__\u001b[0;34m(self, fn, *args, **kwargs)\u001b[0m\n\u001b[1;32m    380\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(do, DoAttempt):\n\u001b[1;32m    381\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 382\u001b[0m         result \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    383\u001b[0m     \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m:  \u001b[38;5;66;03m# noqa: B902\u001b[39;00m\n\u001b[1;32m    384\u001b[0m         retry_state\u001b[38;5;241m.\u001b[39mset_exception(sys\u001b[38;5;241m.\u001b[39mexc_info())  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/langchain/chat_models/openai.py:297\u001b[0m, in \u001b[0;36mChatOpenAI.completion_with_retry.<locals>._completion_with_retry\u001b[0;34m(**kwargs)\u001b[0m\n\u001b[1;32m    295\u001b[0m \u001b[38;5;129m@retry_decorator\u001b[39m\n\u001b[1;32m    296\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_completion_with_retry\u001b[39m(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Any:\n\u001b[0;32m--> 297\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mclient\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/openai/api_resources/chat_completion.py:25\u001b[0m, in \u001b[0;36mChatCompletion.create\u001b[0;34m(cls, *args, **kwargs)\u001b[0m\n\u001b[1;32m     23\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[1;32m     24\u001b[0m     \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 25\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     26\u001b[0m     \u001b[38;5;28;01mexcept\u001b[39;00m TryAgain \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m     27\u001b[0m         \u001b[38;5;28;01mif\u001b[39;00m timeout \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m time\u001b[38;5;241m.\u001b[39mtime() \u001b[38;5;241m>\u001b[39m start \u001b[38;5;241m+\u001b[39m timeout:\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/openai/api_resources/abstract/engine_api_resource.py:155\u001b[0m, in \u001b[0;36mEngineAPIResource.create\u001b[0;34m(cls, api_key, api_base, api_type, request_id, api_version, organization, **params)\u001b[0m\n\u001b[1;32m    129\u001b[0m \u001b[38;5;129m@classmethod\u001b[39m\n\u001b[1;32m    130\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcreate\u001b[39m(\n\u001b[1;32m    131\u001b[0m     \u001b[38;5;28mcls\u001b[39m,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    138\u001b[0m     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mparams,\n\u001b[1;32m    139\u001b[0m ):\n\u001b[1;32m    140\u001b[0m     (\n\u001b[1;32m    141\u001b[0m         deployment_id,\n\u001b[1;32m    142\u001b[0m         engine,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    152\u001b[0m         api_key, api_base, api_type, api_version, organization, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mparams\n\u001b[1;32m    153\u001b[0m     )\n\u001b[0;32m--> 155\u001b[0m     response, _, api_key \u001b[38;5;241m=\u001b[39m \u001b[43mrequestor\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    156\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mpost\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m    157\u001b[0m \u001b[43m        \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    158\u001b[0m \u001b[43m        \u001b[49m\u001b[43mparams\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    159\u001b[0m \u001b[43m        \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    160\u001b[0m \u001b[43m        \u001b[49m\u001b[43mstream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    161\u001b[0m \u001b[43m        \u001b[49m\u001b[43mrequest_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest_id\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    162\u001b[0m \u001b[43m        \u001b[49m\u001b[43mrequest_timeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest_timeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    163\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    165\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m stream:\n\u001b[1;32m    166\u001b[0m         \u001b[38;5;66;03m# must be an iterator\u001b[39;00m\n\u001b[1;32m    167\u001b[0m         \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(response, OpenAIResponse)\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/openai/api_requestor.py:299\u001b[0m, in \u001b[0;36mAPIRequestor.request\u001b[0;34m(self, method, url, params, headers, files, stream, request_id, request_timeout)\u001b[0m\n\u001b[1;32m    278\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrequest\u001b[39m(\n\u001b[1;32m    279\u001b[0m     \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m    280\u001b[0m     method,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    287\u001b[0m     request_timeout: Optional[Union[\u001b[38;5;28mfloat\u001b[39m, Tuple[\u001b[38;5;28mfloat\u001b[39m, \u001b[38;5;28mfloat\u001b[39m]]] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m    288\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Tuple[Union[OpenAIResponse, Iterator[OpenAIResponse]], \u001b[38;5;28mbool\u001b[39m, \u001b[38;5;28mstr\u001b[39m]:\n\u001b[1;32m    289\u001b[0m     result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrequest_raw(\n\u001b[1;32m    290\u001b[0m         method\u001b[38;5;241m.\u001b[39mlower(),\n\u001b[1;32m    291\u001b[0m         url,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    297\u001b[0m         request_timeout\u001b[38;5;241m=\u001b[39mrequest_timeout,\n\u001b[1;32m    298\u001b[0m     )\n\u001b[0;32m--> 299\u001b[0m     resp, got_stream \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_interpret_response\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresult\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstream\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    300\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m resp, got_stream, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mapi_key\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/openai/api_requestor.py:710\u001b[0m, in \u001b[0;36mAPIRequestor._interpret_response\u001b[0;34m(self, result, stream)\u001b[0m\n\u001b[1;32m    702\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m (\n\u001b[1;32m    703\u001b[0m         \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_interpret_response_line(\n\u001b[1;32m    704\u001b[0m             line, result\u001b[38;5;241m.\u001b[39mstatus_code, result\u001b[38;5;241m.\u001b[39mheaders, stream\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m    705\u001b[0m         )\n\u001b[1;32m    706\u001b[0m         \u001b[38;5;28;01mfor\u001b[39;00m line \u001b[38;5;129;01min\u001b[39;00m parse_stream(result\u001b[38;5;241m.\u001b[39miter_lines())\n\u001b[1;32m    707\u001b[0m     ), \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m    708\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    709\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m (\n\u001b[0;32m--> 710\u001b[0m         \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_interpret_response_line\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    711\u001b[0m \u001b[43m            \u001b[49m\u001b[43mresult\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcontent\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdecode\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mutf-8\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    712\u001b[0m \u001b[43m            \u001b[49m\u001b[43mresult\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstatus_code\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    713\u001b[0m \u001b[43m            \u001b[49m\u001b[43mresult\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m    714\u001b[0m \u001b[43m            \u001b[49m\u001b[43mstream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[1;32m    715\u001b[0m \u001b[43m        \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m    716\u001b[0m         \u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[1;32m    717\u001b[0m     )\n",
      "File \u001b[0;32m/opt/conda/lib/python3.11/site-packages/openai/api_requestor.py:775\u001b[0m, in \u001b[0;36mAPIRequestor._interpret_response_line\u001b[0;34m(self, rbody, rcode, rheaders, stream)\u001b[0m\n\u001b[1;32m    773\u001b[0m stream_error \u001b[38;5;241m=\u001b[39m stream \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124merror\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m resp\u001b[38;5;241m.\u001b[39mdata\n\u001b[1;32m    774\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m stream_error \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;241m200\u001b[39m \u001b[38;5;241m<\u001b[39m\u001b[38;5;241m=\u001b[39m rcode \u001b[38;5;241m<\u001b[39m \u001b[38;5;241m300\u001b[39m:\n\u001b[0;32m--> 775\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhandle_error_response(\n\u001b[1;32m    776\u001b[0m         rbody, rcode, resp\u001b[38;5;241m.\u001b[39mdata, rheaders, stream_error\u001b[38;5;241m=\u001b[39mstream_error\n\u001b[1;32m    777\u001b[0m     )\n\u001b[1;32m    778\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m resp\n",
      "\u001b[0;31mInvalidRequestError\u001b[0m: This model's maximum context length is 4097 tokens. However, you requested 4111 tokens (21 in the messages, 4090 in the completion). Please reduce the length of the messages or completion."
     ]
    }
   ],
   "source": [
    "# 但是 LLM 的输入 Token 是有限的，总该不能一直塞进去吧\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=4090,\n",
    ")\n",
    "\n",
    "messages = [\n",
    "    HumanMessage(content=\"用20个字介绍下歌手赵雷\"),\n",
    "]\n",
    "\n",
    "llm(messages).content"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e2c44f9-1419-49ff-abc6-e15b5cb951b8",
   "metadata": {},
   "source": [
    "#### ConversationBufferMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "089d33fc-9fb8-4088-a8df-1c5ce3584e5c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用 LangChain Memory 处理\n",
    "# 存储每次对话的内容\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain.chains import ConversationChain\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "memory = ConversationBufferMemory()\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "8dfde278-fd23-44a3-9cc3-ea11cb4dfab4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e6cb3f02-e807-4882-ba69-af6853912a88",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'你刚问我用20个字介绍下歌手赵雷。'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"我刚问你什么了\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "afedaf96-1c5f-4980-9a1c-e1bb481a89d9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatMessageHistory(messages=[HumanMessage(content='用20个字介绍下歌手赵雷'), AIMessage(content='赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。'), HumanMessage(content='我刚问你什么了'), AIMessage(content='你刚问我用20个字介绍下歌手赵雷。')])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 很好，不需要自己在去 Append 手动处理记忆了\n",
    "# 来看看 Memory 究竟存储了些什么\n",
    "memory.chat_memory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "43f657a6-df88-422f-9da8-770586504931",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI: 赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。\n",
      "Human: 我刚问你什么了\n",
      "AI: 你刚问我用20个字介绍下歌手赵雷。\n"
     ]
    }
   ],
   "source": [
    "print(memory.buffer)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55079f0d-dc7a-48a6-8969-e5ad75598c28",
   "metadata": {},
   "source": [
    "#### ConversationBufferWindowMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e164e7b3-9ec3-4150-96ef-d8caf6963c6b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 但这种基于全部对话内容的记忆，在多轮对话后也会超过 LLM 限制\n",
    "# 是否有使用最近的对话轮次作为记忆就行了\n",
    "from langchain.memory import ConversationBufferWindowMemory\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "memory = ConversationBufferWindowMemory(k=2)\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "53168717-57b5-46f7-86b9-00d1ddc611fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "9f8057df-9498-49fb-8c12-2cedd4abe641",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI: 赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。\n",
      "Human: 他最新的专辑叫什么\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'他最新的专辑叫做《无法长大》。'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"他最新的专辑叫什么\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "133ce303-dfaf-4e5c-ac84-43d2e04a0e6b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI: 赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。\n",
      "Human: 他最新的专辑叫什么\n",
      "AI: 他最新的专辑叫做《无法长大》。\n",
      "Human: 赵雷什么时候开演唱会\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷的演唱会时间我不清楚，抱歉。'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"赵雷什么时候开演唱会\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "c35b8fe6-a3b9-4a3b-98d7-4ffbae771afb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "Human: 他最新的专辑叫什么\n",
      "AI: 他最新的专辑叫做《无法长大》。\n",
      "Human: 赵雷什么时候开演唱会\n",
      "AI: 赵雷的演唱会时间我不清楚，抱歉。\n",
      "Human: 我第一个问题问你什么了？\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'你第一个问题问我赵雷最新的专辑叫什么。'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"我第一个问题问你什么了？\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59ce573d-eead-44e8-9368-b2c35b8dd555",
   "metadata": {},
   "source": [
    "#### ConversationSummaryMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "9b927d4f-9306-472e-82ea-c7bca00fe785",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.memory import ConversationSummaryMemory, ChatMessageHistory\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "memory = ConversationSummaryMemory(llm=llm)\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "ebc3b2a2-3282-4e1a-9a69-6008d3c81634",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "e23286db-8781-4c82-b8fe-732de5d6b4d1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "The human asks the AI to introduce the singer Zhao Lei in 20 words. The AI describes Zhao Lei as a popular Chinese singer known for his unique voice and emotional songs. He has won multiple music awards and is loved by young people for his authentic emotions and social observations.\n",
      "Human: 他最新的专辑叫什么\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'他最新的专辑叫《心的距离》。这张专辑于2020年发行，收录了十首歌曲，展现了赵雷独特的音乐风格和情感表达能力。'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"他最新的专辑叫什么\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "4b799395-a3c8-4768-9015-25564d6b0f9d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "The human asks the AI to introduce the singer Zhao Lei in 20 words. The AI describes Zhao Lei as a popular Chinese singer known for his unique voice and emotional songs. He has won multiple music awards and is loved by young people for his authentic emotions and social observations. Zhao Lei's latest album is called \"Distance of the Heart.\" Released in 2020, it features ten songs that showcase his unique musical style and emotional expression.\n",
      "Human: 我第一个问题问你什么了？\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'你第一个问题问我关于赵雷的介绍。'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"我第一个问题问你什么了？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "46ad566f-623e-413c-b850-e1c60853bc0c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The human asks the AI to introduce the singer Zhao Lei in 20 words. The AI describes Zhao Lei as a popular Chinese singer known for his unique voice and emotional songs. He has won multiple music awards and is loved by young people for his authentic emotions and social observations. Zhao Lei\\'s latest album is called \"Distance of the Heart.\" Released in 2020, it features ten songs that showcase his unique musical style and emotional expression. The human asks the AI what their first question was. The AI responds that the first question was about an introduction to Zhao Lei.'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 很好，不需要自己在去 Append 手动处理记忆了\n",
    "# 来看看 Memory 究竟存储了些什么\n",
    "memory.buffer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "3222e913-d8bb-4340-9f01-b64df6131e0e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'人类要求AI用20个词介绍歌手赵雷。AI将赵雷描述为一位中国知名歌手，以其独特的嗓音和情感歌曲而闻名。他赢得了多个音乐奖项，年轻人喜爱他真实的情感和社会观察。赵雷的最新专辑名为《心之距离》。于2020年发布，其中包含十首展示他独特音乐风格和情感表达的歌曲。人类询问AI的第一个问题是什么。AI回答第一个问题是关于对赵雷的介绍。'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 看不懂？ 翻译下呗\n",
    "messages = [\n",
    "    SystemMessage(content=\"你是一名语言大师\"),\n",
    "    HumanMessage(content=f\"请将给定的英文翻译成中文后输出。 英文: {memory.buffer}\"),\n",
    "]\n",
    "\n",
    "llm(messages).content"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d15c53a-1594-4022-b60a-1484cb1e09d1",
   "metadata": {},
   "source": [
    "#### ConversationSummaryBufferMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "6cf01a57-86bc-424f-b706-66581bdfcece",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于 Token 长度来进行总结\n",
    "from langchain.memory import ConversationSummaryBufferMemory\n",
    " \n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "memory = ConversationSummaryBufferMemory(\n",
    "    llm=llm,\n",
    "    max_token_limit=100\n",
    ")\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "6bb0cd87-e780-4711-96e9-f6bedd8acaa4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。'"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "0fd3ca51-4982-4fe0-bc0d-468a44f3d6db",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "System: The human asks the AI to introduce the singer Zhao Lei in 20 words. The AI describes Zhao Lei as a popular Chinese singer known for his unique voice and emotional songs. He has won multiple music awards and is loved by young people for his authentic emotions and social observations.\n",
      "Human: 他最新的专辑叫什么\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'他最新的专辑叫《我是赵雷》。这张专辑于2020年发布，包含了十首歌曲，其中包括了他的代表作品《成全》和《理想》。这张专辑延续了赵雷一贯的风格，歌曲内容深入人心，充满情感。'"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"他最新的专辑叫什么\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "7dedc3c8-73ed-431f-ab2a-e69c895b4564",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "System: The human asks the AI to introduce the singer Zhao Lei in 20 words. The AI describes Zhao Lei as a popular Chinese singer known for his unique voice and emotional songs. He has won multiple music awards and is loved by young people for his authentic emotions and social observations. Zhao Lei's latest album is called \"I am Zhao Lei\". Released in 2020, it contains ten songs, including his representative works \"Chengquan\" and \"Ideal\". This album continues Zhao Lei's consistent style, with songs that deeply resonate with listeners and are full of emotions.\n",
      "Human: 他的音乐风格是怎样的\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷的音乐风格可以被描述为民谣和摇滚的结合。他的歌曲通常以吉他和钢琴为主要乐器，旋律简洁而富有力量感。他的歌词深情而真实，经常探索人生的苦乐与社会的观察。赵雷的音乐风格独特而个性化，他的歌声充满情感，能够打动人心。'"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"他的音乐风格是怎样的\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "5d558aa2-abb4-47e3-8631-794f5eb76567",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "System: The human asks the AI to introduce the singer Zhao Lei in 20 words. The AI describes Zhao Lei as a popular Chinese singer known for his unique voice and emotional songs. He has won multiple music awards and is loved by young people for his authentic emotions and social observations. Zhao Lei's latest album is called \"I am Zhao Lei\". Released in 2020, it contains ten songs, including his representative works \"Chengquan\" and \"Ideal\". This album continues Zhao Lei's consistent style, with songs that deeply resonate with listeners and are full of emotions. Zhao Lei's music style can be described as a combination of folk and rock. His songs usually feature guitar and piano as the main instruments, with simple yet powerful melodies. His lyrics are heartfelt and genuine, often exploring the joys and sorrows of life and observations of society. Zhao Lei's music style is unique and personalized, and his vocals are full of emotions that can touch people's hearts.\n",
      "Human: 他的最近有开演唱会的计划吗\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'是的，赵雷最近有开演唱会的计划。他计划在2022年进行一系列巡回演唱会，包括在中国各大城市的演出。具体的演唱会日期和地点还没有公布，但是他的粉丝们非常期待他的演出。赵雷的演唱会通常会吸引大量的观众，因为他的音乐能够打动人心，让人们沉浸在他的情感世界中。所以如果你是赵雷的粉丝，可以密切关注他的官方消息，以获取最新的演唱会信息。'"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"他的最近有开演唱会的计划吗\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "e58d9aad-1e0d-4bc7-9377-bd2d62445518",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'The human asks the AI to introduce the singer Zhao Lei in 20 words. The AI describes Zhao Lei as a popular Chinese singer known for his unique voice and emotional songs. He has won multiple music awards and is loved by young people for his authentic emotions and social observations. Zhao Lei\\'s latest album is called \"I am Zhao Lei\". Released in 2020, it contains ten songs, including his representative works \"Chengquan\" and \"Ideal\". This album continues Zhao Lei\\'s consistent style, with songs that deeply resonate with listeners and are full of emotions. Zhao Lei\\'s music style can be described as a combination of folk and rock. His songs usually feature guitar and piano as the main instruments, with simple yet powerful melodies. His lyrics are heartfelt and genuine, often exploring the joys and sorrows of life and observations of society. Zhao Lei\\'s music style is unique and personalized, and his vocals are full of emotions that can touch people\\'s hearts. Zhao Lei has plans to hold a series of concerts in 2022, including performances in major cities in China. The specific concert dates and locations have not been announced yet, but his fans are eagerly anticipating his shows. Zhao Lei\\'s concerts usually attract a large audience because his music has the power to move people and immerse them in his emotional world. If you are a fan of Zhao Lei, it is recommended to closely follow his official updates to get the latest concert information.'"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.memory.moving_summary_buffer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f648185c-18ba-4819-9055-162dabfb27e5",
   "metadata": {},
   "source": [
    "#### ConversationTokenBufferMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "9947319c-dd22-4678-b26f-112e184bbdc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于 Token 的长度来决定记忆力\n",
    "from langchain.memory import ConversationTokenBufferMemory\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "memory = ConversationTokenBufferMemory(\n",
    "    llm=llm,\n",
    "    max_token_limit=10,\n",
    "    return_messages=True\n",
    ")\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "1ac46860-b9e7-449b-a616-57ec8de567b8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "[]\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他的音乐风格多样，包括摇滚、民谣和流行音乐等。赵雷的歌曲通常富有情感，歌词深入人心，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷的音乐才华和独特的艺术风格使他成为中国乐坛的重要人物之一。'"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "06aa2d9a-7d06-4a60-9029-a70eb7819754",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "[]\n",
      "Human: 他叫什么名字\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'他叫李明。'"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"他叫什么名字\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "33ce807c-df64-431d-9c77-a3e33cd05f0e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 改成更多长度的 Token \n",
    "memory = ConversationTokenBufferMemory(\n",
    "    llm=llm,\n",
    "    max_token_limit=500,\n",
    "    return_messages=True\n",
    ")\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "650ef1e8-cf4b-4599-a4fd-ffdd4199661b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "[]\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他的音乐风格多样，包括摇滚、民谣和流行音乐等。赵雷的歌曲通常富有情感，歌词深入人心，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷的音乐才华和独特的艺术风格使他成为中国乐坛的重要人物之一。'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "ad0dd6f7-3896-4509-8367-d0cf3f867c8b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "[HumanMessage(content='用20个字介绍下歌手赵雷'), AIMessage(content='赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他的音乐风格多样，包括摇滚、民谣和流行音乐等。赵雷的歌曲通常富有情感，歌词深入人心，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷的音乐才华和独特的艺术风格使他成为中国乐坛的重要人物之一。')]\n",
      "Human: 他叫什么名字\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'他叫赵雷。'"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"他叫什么名字\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93c5c4c7-737e-44fa-af5a-696af6912a02",
   "metadata": {},
   "source": [
    "#### ConversationEntityMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "ed1de245-0fb5-4fb2-85ef-bd0308039261",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 命名识别抽取，将对话中的实体进行识别作为记忆\n",
    "from langchain.memory import ConversationEntityMemory\n",
    "from langchain.memory.prompt import ENTITY_MEMORY_CONVERSATION_TEMPLATE\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "memory = ConversationEntityMemory(llm=llm)\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    prompt=ENTITY_MEMORY_CONVERSATION_TEMPLATE,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "ca7f2257-84f4-4269-a8b1-0ea64d008908",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mYou are an assistant to a human, powered by a large language model trained by OpenAI.\n",
      "\n",
      "You are designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, you are able to generate human-like text based on the input you receive, allowing you to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\n",
      "\n",
      "You are constantly learning and improving, and your capabilities are constantly evolving. You are able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. You have access to some personalized information provided by the human in the Context section below. Additionally, you are able to generate your own text based on the input you receive, allowing you to engage in discussions and provide explanations and descriptions on a wide range of topics.\n",
      "\n",
      "Overall, you are a powerful tool that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether the human needs help with a specific question or just wants to have a conversation about a particular topic, you are here to assist.\n",
      "\n",
      "Context:\n",
      "{'赵雷': ''}\n",
      "\n",
      "Current conversation:\n",
      "\n",
      "Last line:\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "You:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位才华横溢的中国歌手，以其深情的歌曲和独特的嗓音而闻名。他的音乐作品充满了对生活、爱情和社会问题的思考，深深触动着人们的心灵。赵雷的歌曲既有力量感又充满温暖，他的歌声能够引起人们共鸣，让人们感受到真实的情感和情感的力量。无论是在舞台上还是在录音室里，赵雷都展现出了他的独特魅力和音乐才华，成为了中国乐坛的一颗耀眼之星。'"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "b909be1e-976f-4912-b498-780c5b22612e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'赵雷': '赵雷是一位才华横溢的中国歌手，以其深情的歌曲和独特的嗓音而闻名，他的歌声能够引起人们共鸣，让人们感受到真实的情感和情感的力量。'}"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.memory.entity_store.store"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5143f6f-80f5-45d5-b95d-ba6f016c388d",
   "metadata": {},
   "source": [
    "#### ConversationKGMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "e9719e0e-d855-45e3-b4b4-b6c4bc357856",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 通过知识图谱的方式\n",
    "from langchain.memory import ConversationKGMemory\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "memory = ConversationKGMemory(llm=llm)\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "d57e1a92-6314-4662-865a-cf2a794c8776",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。他以其独特的嗓音和深情的歌曲而闻名，曾获得多个音乐奖项，包括中国音乐金钟奖和音乐风云榜年度最佳男歌手奖。他的歌曲通常以真实的情感和社会观察为主题，深受年轻人的喜爱。'"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "208d20ea-144f-4a0a-afef-4e906be09214",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Current conversation:\n",
      "\n",
      "Human: 用20个字介绍下南山南这首歌\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'《南山南》是一首由马頔创作的歌曲，最初收录于2012年发行的专辑《南山南》中。这首歌以南京市南山为背景，描述了一个关于爱情和离别的故事。歌曲的旋律优美动人，歌词深情而富有感染力，因此深受广大听众喜爱。'"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下南山南这首歌\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "0709717d-28b7-401e-9189-dfffc6002297",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['赵雷', '中国', '1992年', '北京现代音乐研修学院']"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 获取实体\n",
    "memory.get_current_entities(\"赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "59a403fd-4320-42e6-a0a0-386cb85f9d0a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[KnowledgeTriple(subject='赵雷', predicate='是一位', object_='中国流行歌手'),\n",
       " KnowledgeTriple(subject='赵雷', predicate='出生于', object_='1992年'),\n",
       " KnowledgeTriple(subject='赵雷', predicate='毕业于', object_='北京现代音乐研修学院')]"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 更模块化地从新消息中获取知识三元组\n",
    "memory.get_knowledge_triplets(\"赵雷是一位中国流行歌手，出生于1992年，毕业于北京现代音乐研修学院。\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa9fbf63-49b4-49d1-acb6-83809e0ff3f8",
   "metadata": {},
   "source": [
    "#### VectorStoreRetrieverMemory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "c9bc8022-90e8-4c45-90a5-71d0b10f9e7a",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "`embedding_function` is expected to be an Embeddings object, support for passing in a function will soon be removed.\n"
     ]
    }
   ],
   "source": [
    "# 外挂向量数据库提供记忆，让记忆变得无限\n",
    "import faiss\n",
    "from langchain.embeddings.openai import OpenAIEmbeddings\n",
    "from langchain.docstore import InMemoryDocstore\n",
    "from langchain.vectorstores import FAISS\n",
    "\n",
    "index = faiss.IndexFlatL2(1536)\n",
    "embedding_fn = OpenAIEmbeddings().embed_query\n",
    "vectorstore = FAISS(embedding_fn, index, InMemoryDocstore({}), {})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "be4108c7-261d-4d09-a820-5d4eff6e1499",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 通过去向量数据库召回相似文档充当记忆\n",
    "from langchain.memory import VectorStoreRetrieverMemory\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "_DEFAULT_TEMPLATE = \"\"\"The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
    "\n",
    "Relevant pieces of previous conversation:\n",
    "{history}\n",
    "\n",
    "(You do not need to use these pieces of information if not relevant)\n",
    "\n",
    "Current conversation:\n",
    "Human: {input}\n",
    "AI:\"\"\"\n",
    "\n",
    "PROMPT = PromptTemplate(\n",
    "    input_variables=[\"history\", \"input\"], template=_DEFAULT_TEMPLATE\n",
    ")\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "retriever = vectorstore.as_retriever(search_kwargs=dict(k=2))\n",
    "memory = VectorStoreRetrieverMemory(retriever=retriever)\n",
    "\n",
    "conversation = ConversationChain(\n",
    "    llm=llm,\n",
    "    memory=memory,\n",
    "    prompt=PROMPT,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "6c775994-ab31-4819-ad26-4b1a53498ea2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Relevant pieces of previous conversation:\n",
      "\n",
      "\n",
      "(You do not need to use these pieces of information if not relevant)\n",
      "\n",
      "Current conversation:\n",
      "Human: 用20个字介绍下歌手赵雷\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他出生于1992年，来自中国河北省。赵雷的音乐风格多样，包括摇滚、民谣和流行音乐。他的歌曲通常以真实的情感和深刻的歌词而著称，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷在中国乐坛有着广泛的影响力，被认为是一位才华横溢的歌手。'"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"用20个字介绍下歌手赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "bfd2b997-cc32-4f01-96bd-2a2cab623a22",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Relevant pieces of previous conversation:\n",
      "input: 用20个字介绍下歌手赵雷\n",
      "response: 赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他出生于1992年，来自中国河北省。赵雷的音乐风格多样，包括摇滚、民谣和流行音乐。他的歌曲通常以真实的情感和深刻的歌词而著称，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷在中国乐坛有着广泛的影响力，被认为是一位才华横溢的歌手。\n",
      "\n",
      "(You do not need to use these pieces of information if not relevant)\n",
      "\n",
      "Current conversation:\n",
      "Human: 如何制作一个披萨，简单的告诉我\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'制作披萨的步骤非常简单。首先，你需要准备面团。你可以将面粉、酵母、盐和水混合在一起，搅拌至面团光滑。然后，将面团放在一个温暖的地方发酵，直到它变得蓬松起来。\\n\\n接下来，你需要准备披萨酱。你可以用番茄酱、番茄酱、大蒜、盐和一些香料来制作。将所有的材料混合在一起，搅拌均匀。\\n\\n然后，你可以选择添加你喜欢的配料。常见的配料有奶酪、蔬菜、肉类和海鲜等。你可以根据自己的口味选择。\\n\\n接下来，将面团擀成圆形，并在上面涂抹一层薄薄的披萨酱。然后，将配料均匀地撒在面团上。\\n\\n最后，将披萨放入预热至200摄氏度的烤箱中，烤约15-20分钟，或直到奶酪融化和金黄色。\\n\\n制作披萨非常简单，你可以根据自己的口味和喜好进行创意搭配。祝你制作美味的披萨！'"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"如何制作一个披萨，简单的告诉我\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "f99b05f0-67d4-403a-809c-95cbe6ed2d87",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Relevant pieces of previous conversation:\n",
      "input: 如何制作一个披萨，简单的告诉我\n",
      "response: 制作披萨的步骤非常简单。首先，你需要准备面团。你可以将面粉、酵母、盐和水混合在一起，搅拌至面团光滑。然后，将面团放在一个温暖的地方发酵，直到它变得蓬松起来。\n",
      "\n",
      "接下来，你需要准备披萨酱。你可以用番茄酱、番茄酱、大蒜、盐和一些香料来制作。将所有的材料混合在一起，搅拌均匀。\n",
      "\n",
      "然后，你可以选择添加你喜欢的配料。常见的配料有奶酪、蔬菜、肉类和海鲜等。你可以根据自己的口味选择。\n",
      "\n",
      "接下来，将面团擀成圆形，并在上面涂抹一层薄薄的披萨酱。然后，将配料均匀地撒在面团上。\n",
      "\n",
      "最后，将披萨放入预热至200摄氏度的烤箱中，烤约15-20分钟，或直到奶酪融化和金黄色。\n",
      "\n",
      "制作披萨非常简单，你可以根据自己的口味和喜好进行创意搭配。祝你制作美味的披萨！\n",
      "input: 用20个字介绍下歌手赵雷\n",
      "response: 赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他出生于1992年，来自中国河北省。赵雷的音乐风格多样，包括摇滚、民谣和流行音乐。他的歌曲通常以真实的情感和深刻的歌词而著称，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷在中国乐坛有着广泛的影响力，被认为是一位才华横溢的歌手。\n",
      "\n",
      "(You do not need to use these pieces of information if not relevant)\n",
      "\n",
      "Current conversation:\n",
      "Human: 法拉利和兰博基尼哪一个驾驶体验好\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'法拉利和兰博基尼都是世界上著名的豪华跑车品牌，它们都提供了独特而令人兴奋的驾驶体验。然而，每个人对于驾驶体验的定义可能有所不同，因此无法一概而论哪个更好。\\n\\n法拉利以其卓越的操控性能和高速驾驶体验而闻名。它们通常具有强大的发动机和先进的悬挂系统，可以提供出色的加速和操控能力。法拉利的驾驶座位通常更加贴合身体，给予驾驶者更直接的驾驶感受。\\n\\n兰博基尼则以其独特的外观设计和强大的动力而著称。兰博基尼的车身线条流畅而动感，给人一种强烈的视觉冲击力。它们通常搭载高性能发动机，可以提供令人兴奋的加速和极高的最高速度。\\n\\n总的来说，法拉利和兰博基尼都是顶级的豪华跑车品牌，它们都提供了令人难忘的驾驶体验。选择哪个更好取决于个人的喜好和需求。如果你更注重操控性能和驾驶感受，那么法拉利可能更适合你。如果你更注重外观设计和动力表现，那么兰博基尼可能更适合你。最好的方式是亲自试驾这些车辆，以便亲身体验它们的驾驶感受。'"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"法拉利和兰博基尼哪一个驾驶体验好\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "2ac13587-3a97-42b8-acbe-39fdb0621804",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Relevant pieces of previous conversation:\n",
      "input: 用20个字介绍下歌手赵雷\n",
      "response: 赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他出生于1992年，来自中国河北省。赵雷的音乐风格多样，包括摇滚、民谣和流行音乐。他的歌曲通常以真实的情感和深刻的歌词而著称，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷在中国乐坛有着广泛的影响力，被认为是一位才华横溢的歌手。\n",
      "input: 法拉利和兰博基尼哪一个驾驶体验好\n",
      "response: 法拉利和兰博基尼都是世界上著名的豪华跑车品牌，它们都提供了独特而令人兴奋的驾驶体验。然而，每个人对于驾驶体验的定义可能有所不同，因此无法一概而论哪个更好。\n",
      "\n",
      "法拉利以其卓越的操控性能和高速驾驶体验而闻名。它们通常具有强大的发动机和先进的悬挂系统，可以提供出色的加速和操控能力。法拉利的驾驶座位通常更加贴合身体，给予驾驶者更直接的驾驶感受。\n",
      "\n",
      "兰博基尼则以其独特的外观设计和强大的动力而著称。兰博基尼的车身线条流畅而动感，给人一种强烈的视觉冲击力。它们通常搭载高性能发动机，可以提供令人兴奋的加速和极高的最高速度。\n",
      "\n",
      "总的来说，法拉利和兰博基尼都是顶级的豪华跑车品牌，它们都提供了令人难忘的驾驶体验。选择哪个更好取决于个人的喜好和需求。如果你更注重操控性能和驾驶感受，那么法拉利可能更适合你。如果你更注重外观设计和动力表现，那么兰博基尼可能更适合你。最好的方式是亲自试驾这些车辆，以便亲身体验它们的驾驶感受。\n",
      "\n",
      "(You do not need to use these pieces of information if not relevant)\n",
      "\n",
      "Current conversation:\n",
      "Human: 推荐5个民谣风格的歌手\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'推荐5个民谣风格的歌手，我可以给你一些例子。首先，赵雷是一位中国流行歌手，他的音乐风格包括摇滚、民谣和流行音乐。他的歌曲通常以真实的情感和深刻的歌词而著称。其次，李志也是一位中国民谣歌手，他的歌曲常常反映社会现实和人生哲理。第三，宋冬野是另一位备受喜爱的中国民谣歌手，他的歌曲充满了温暖和情感。第四，周云蓬是中国台湾的民谣歌手，他的音乐风格独特而富有感染力。最后，如果你喜欢国外的民谣歌手，我可以推荐Bob Dylan和Simon & Garfunkel，他们都是世界级的民谣音乐代表。希望这些推荐对你有帮助！'"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"推荐5个民谣风格的歌手\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "500a89a5-6aab-4ba6-be13-fd0ee823984a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new ConversationChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
      "\n",
      "Relevant pieces of previous conversation:\n",
      "input: 推荐5个民谣风格的歌手\n",
      "response: 推荐5个民谣风格的歌手，我可以给你一些例子。首先，赵雷是一位中国流行歌手，他的音乐风格包括摇滚、民谣和流行音乐。他的歌曲通常以真实的情感和深刻的歌词而著称。其次，李志也是一位中国民谣歌手，他的歌曲常常反映社会现实和人生哲理。第三，宋冬野是另一位备受喜爱的中国民谣歌手，他的歌曲充满了温暖和情感。第四，周云蓬是中国台湾的民谣歌手，他的音乐风格独特而富有感染力。最后，如果你喜欢国外的民谣歌手，我可以推荐Bob Dylan和Simon & Garfunkel，他们都是世界级的民谣音乐代表。希望这些推荐对你有帮助！\n",
      "input: 用20个字介绍下歌手赵雷\n",
      "response: 赵雷是一位中国流行歌手，以其深情的歌曲和独特的嗓音而闻名。他出生于1992年，来自中国河北省。赵雷的音乐风格多样，包括摇滚、民谣和流行音乐。他的歌曲通常以真实的情感和深刻的歌词而著称，深受听众喜爱。他的代表作品包括《成全》、《画》和《理想》等。赵雷在中国乐坛有着广泛的影响力，被认为是一位才华横溢的歌手。\n",
      "\n",
      "(You do not need to use these pieces of information if not relevant)\n",
      "\n",
      "Current conversation:\n",
      "Human: 南山南这首歌你觉得如何\n",
      "AI:\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'南山南是一首非常著名的中国民谣歌曲，由马頔创作。这首歌以其深情的旋律和感人的歌词而闻名。它讲述了一个关于离别和思念的故事，引起了许多人的共鸣。许多人认为这首歌非常动听，充满了情感和温暖。它也被广泛地演唱和翻唱，成为了中国民谣音乐的经典之作。我个人也非常喜欢这首歌，它让人感受到了深深的情感和温暖。你喜欢这首歌吗？'"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conversation.predict(input=\"南山南这首歌你觉得如何\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6025da80-8ba6-495d-a398-080106d5d054",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "b6dab97e-695a-4737-821f-8f2a5cc48b6f",
   "metadata": {},
   "source": [
    "### Chains"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "7cdb51ad-d759-4a44-aa94-3f184bbf26a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Chian 是整一个 LangChain 项目中的灵魂，很多时不是仅仅用 LLM 来完成任务，复杂的场景还需要链接其他的组件，这就是 Chain\n",
    "# 1. LLMChain\n",
    "# 2. LLMRouterChain\n",
    "# 3. SequentialChain\n",
    "# 4. TransformChain"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "764085ed-cdf6-4967-807f-4fd1671d9dc9",
   "metadata": {},
   "source": [
    "#### ConversationChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "b2bd9707-37b4-43f3-8ef2-cadb9d284b73",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 刚刚我们一直在用一个叫做 ConversationChain 实际上，他就是来帮助我们进行多轮对话的（带有记忆力）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35394fcb-0251-4306-8783-935719533597",
   "metadata": {},
   "source": [
    "#### LLMChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "f9c6cacc-cefc-493b-8dd4-5acfa01d58a0",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import LLMChain\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "prompt_template = \"请回答 {name} 是什么时候出生的\"\n",
    "\n",
    "llm_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "de532fcb-bd2e-421e-9fb3-febdb5312268",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['name'], template='请回答 {name} 是什么时候出生的')"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 提示词模版，其实就是为了复用\n",
    "# 需要把输入参数进行赋值 \n",
    "PromptTemplate.from_template(prompt_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "b18b9dc9-2938-428f-922c-6df70fe1f8d6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': '赵雷', 'text': '赵雷是1992年8月12日出生的。'}"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 可以见到在模版中的占位符实际上会被替换\n",
    "llm_chain(inputs={\"name\": \"赵雷\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "9bd988f2-0039-42cb-aa32-7a3153c8c12c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': '赵雷', 'text': '赵雷是1992年8月12日出生的。'}"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果是只有一个键的时候，也可以直接不写键名\n",
    "llm_chain(\"赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "0a8c2668-f8c7-4f99-986e-b9bb571a9a65",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'赵雷是1992年8月12日出生的。'"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果是 Run 方法就直接是输出\n",
    "llm_chain.run(\"赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "c2c188d5-2e3a-4f74-b126-3d14a219ce09",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'text': '赵雷是1992年8月12日出生的。'}"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 只需要返回答案\n",
    "llm_chain(inputs={\"name\": \"赵雷\"}, return_only_outputs=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "ceedb29d-d603-4e20-84d8-ef0f0005dba2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'text': '很抱歉，我无法回答你的问题。请提供更多细节或者重新提问。'}"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 不存在记忆能力，只是最简单的一问一答没有上下文\n",
    "llm_chain(inputs={\"name\": \"我刚刚问的是哪一个人\"}, return_only_outputs=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "bcdec26a-4f67-49f0-ae78-a3490fb10161",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['text']"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 输出的 Key，后续需要用到这个 Key 作为输入\n",
    "llm_chain.output_keys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "1da1a611-c1ae-4078-b3d9-af51e4c44bdf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['result']"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 也可以指定下输出的 Key 名\n",
    "llm_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template), output_key=\"result\")\n",
    "llm_chain.output_keys"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6a941a5-e5aa-4d07-bd60-7f1b939328eb",
   "metadata": {},
   "source": [
    "#### LLMMathChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "536951bc-95bc-440c-a52e-60b97ae3ba03",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 救赎 LLM 算术能力差的问题\n",
    "from langchain.chains import LLMMathChain\n",
    " \n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=1024,\n",
    ")\n",
    "\n",
    "prompt = \"请回答 369*852 等于多少\"\n",
    "\n",
    "llm_math_chain = LLMMathChain(\n",
    "    llm=llm,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "f2ea9094-add3-40ab-9a8a-62eb010d49be",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMMathChain chain...\u001b[0m\n",
      "请回答 369*852 等于多少\u001b[32;1m\u001b[1;3m```text\n",
      "369 * 852\n",
      "```\n",
      "...numexpr.evaluate(\"369 * 852\")...\n",
      "\u001b[0m\n",
      "Answer: \u001b[33;1m\u001b[1;3m314388\u001b[0m\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Answer: 314388'"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm_math_chain.run(prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "56d2d743-16f6-48fc-9676-4aba55af74b4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "314388\n"
     ]
    }
   ],
   "source": [
    "# 看看答案是否一样\n",
    "print(369*852)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "8202499b-82db-4404-8ec3-0964a5edc7ac",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实际上就是抽取对应的数字、运算，然后给到 Numexpre 进行求解\n",
    "# 毕竟编程语言的解释器是不会计算错误的"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03a2181b-7c10-4b9c-9498-94442f0da480",
   "metadata": {},
   "source": [
    "#### LLMRequestsChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "e4ccb748-01aa-44b7-83c4-fe7a9144c043",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 完善 LLM 无法获取最新的知识\n",
    "from langchain.chains import LLMRequestsChain\n",
    " \n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=1024,\n",
    ")\n",
    "\n",
    "template = \"\"\"\n",
    "1. 系统会提供 Google 的原始搜索结果。\n",
    "2. 请把根据用户问题从原始搜索结果提取答案。\n",
    "3. 如果里面没有相关信息的话就说\"找不到\"。\n",
    "\n",
    "原始搜索结果:\n",
    "{requests_result}\n",
    "\n",
    "用户问题:\n",
    "{question}\n",
    "\"\"\"\n",
    "\n",
    "prompt = PromptTemplate(\n",
    "    input_variables=['question', 'requests_result'],\n",
    "    template=template,\n",
    ")\n",
    "\n",
    "llm_chain=LLMChain(\n",
    "    llm=llm, \n",
    "    prompt=prompt,\n",
    "    verbose=True\n",
    ")\n",
    "    \n",
    "llm_requests_chain=LLMRequestsChain(\n",
    "    llm_chain=llm_chain,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "d31a9494-86f6-4fae-af13-05ea880e5b71",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMRequestsChain chain...\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m\n",
      "1. 系统会提供 Google 的原始搜索结果。\n",
      "2. 请把根据用户问题从原始搜索结果提取答案。\n",
      "3. 如果里面没有相关信息的话就说\"找不到\"。\n",
      "\n",
      "原始搜索结果:\n",
      "赵雷最近发布了什么新专辑 - Google 搜尋若您在數秒內仍未能自動跳轉，請點擊這裏。無障礙功能連結跳至主內容 停用連續捲動功能啟用連續捲動功能無障礙功能說明無障礙功能意見  按下 / 便可跳至搜尋框赵雷最近发布了什么新专辑             顯示更多刪除刪除舉報不當的預測    搜尋模式全部新聞圖片影片書籍更多工具安全搜尋約 3,110,000 項搜尋結果 (0.44 秒)   搜尋結果 趙雷/最新專輯署前街少年2022 年8月29日00：00，民谣歌手赵雷发布了新专辑《署前街少年》。2022年8月30日赵雷阔别六年再发新专辑，《署前街少年》上线销售破300万Sohuhttps://www.sohu.com › ...Sohuhttps://www.sohu.com › ...其他人也搜尋了以下項目趙小雷2011 年，趙雷縱橫四海2022 年，李榮浩娛樂自己2022 年，HUSH無數2022 年，薛之謙馬拉美的星期二2022 年，吳青峰啓示錄2022 年，鄧紫棋杰倫2000 年，周杰倫選擇您要提供意見的範疇或提供一般意見意見 赵雷最新专辑今日头条https://www.toutiao.com › keyword今日头条https://www.toutiao.com › keyword · 轉為繁體網頁8月29日00:00，民谣歌手赵雷发布了新专辑《署前街少年》。自2017年参加湖南卫视 ... 最近呢，赵雷上线了他的新专辑《署前街少年》，其中大多数歌曲都是非常好听，比如 ...赵雷阔别六年再发新专辑，《署前街少年》上线销售破300万腾讯新闻https://new.qq.com › rain腾讯新闻https://new.qq.com › rain · 轉為繁體網頁2022年8月30日 — 8月29日00：00，民谣歌手赵雷发布了新专辑《署前街少年》。该数字专辑共收录了10首歌曲，售价25元/张。截至8月30日17：00，该专辑已在网易云音乐售 ...補充結果選擇您要提供意見的範疇或提供一般意見      署前街少年      趙雷的音樂專輯              歌曲Teen on Shuqian Street5:04Captain5:51Nights at Sanlitun5:09Cheng Aiying5:01 聆聽SpotifyYouTube MusicApple Music  您喜歡這張專輯嗎？       已表示喜歡        已表示不喜歡    演出者： 趙雷    更多署前街少年的相關資訊   意見如何评价赵雷的新专辑《署前街少年》？知乎https://www.zhihu.com › question知乎https://www.zhihu.com › question · 轉為繁體網頁2022年8月27日 — 时隔六年，赵雷发布了第四张专辑《署前街少年》。 这次专辑当中，最令我意外的是乐队成员。吉他手里没有了喜子，鼓手不是李彦超了，贝斯也不是天佑了……一看制作名单 ...155 個答案  ·  最佳解答: 署前街是北京房山的一条街道，而赵雷就是北京房山人。这次以“署前街少 ...赵雷的新专辑<<无法长大>>收录的歌里都有哪些动人的故事？2016年12月22日赵雷的新专辑《署前街少年》里哪几首歌最好听、最令人感动？2022年9月25日如何评价赵雷的最新专辑署前街少年? - 热心市民史先生的回答2022年10月18日www.zhihu.com 的其他相關資訊赵雷什么时候出新专辑抖音https://www.douyin.com › zhuanti抖音https://www.douyin.com › zhuanti · 轉為繁體網頁赵雷什么时候出新专辑 · 阔别6年，赵雷新专辑《署前街少年》于2022年8 · 赵雷全新个人专辑预计将于8月29日零点发行上线， · 分享一首#赵雷2022年新专辑#署前 ...赵雷- 维基百科，自由的百科全书Wikipediahttps://zh.wikipedia.org › wiki › 赵雷Wikipediahttps://zh.wikipedia.org › wiki › 赵雷 · 轉為繁體網頁... 《新九拍》中；10月发布第二张个人专辑《吉姆餐厅》。 2015年，1月的“年度独立音乐颁奖”他被评为“年度十大音乐人”，专辑《吉姆餐厅》也被评为“年度十大专辑”；9月23 ...曾在《歌手》爆红的他, 新歌令全网崩溃网易https://www.163.com › article网易https://www.163.com › article · 轉為繁體網頁2023年2月9日 — 这段歌词来自赵雷时隔六年，发布的新专辑《署前街少年》中，最受欢迎的一首，名叫《我记得》。 六年磨一剑，赵雷的这张《署前街少年》，不论是对自己这些 ...赵雷Apple Musichttps://music.apple.com › artist › 赵雷Apple Musichttps://music.apple.com › artist › 赵雷 · 轉為繁體網頁2023年10月16日 — 赵雷. 最新发布. 2023年10月16日. 欠父亲的话(电影《我爸没说的那件事》主题曲) - Single. 1 首歌曲. 歌曲排行. 我记得. 署前街少年 · 2022年. 成都. 成都 ...赵雷_百度百科百度百科https://baike.baidu.com › item › 赵雷百度百科https://baike.baidu.com › item › 赵雷 · 轉為繁體網頁2011年，推出首张个人音乐专辑《赵小雷》。2014年，参加CCTV-3原创音乐真人秀节目《中国好歌曲第一季》，获得刘欢组8强；同年，推出第2张个人音乐专辑《吉姆餐厅》。2016年 ...趙雷的熱門歌曲與歷年專輯MyMusichttps://www.mymusic.net.tw › singer › showMyMusichttps://www.mymusic.net.tw › singer › show2014年趙雷《吉姆餐廳》發佈，立刻成為各大平臺的收聽冠軍。14年10月在星光現場的 ... 12月21日，趙雷的新專輯《無法長大》在網易雲音樂獨家首發，這也是趙雷首次嘗試 ...Page Navigation更多結果再試一次    頁尾連結  \n",
      "\n",
      "用户问题:\n",
      "赵雷最近发布了什么新专辑\n",
      "\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'question': '赵雷最近发布了什么新专辑',\n",
       " 'url': 'https://www.google.com/search?q=赵雷最近发布了什么新专辑',\n",
       " 'output': '赵雷最近发布了新专辑《署前街少年》。'}"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "question = \"赵雷最近发布了什么新专辑\"\n",
    "\n",
    "inputs = {\n",
    "    \"question\": question,\n",
    "    \"url\": \"https://www.google.com/search?q=\" + question.replace(' ', '+')\n",
    "}\n",
    "\n",
    "llm_requests_chain(inputs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "720f5308-e29b-4efc-84f8-8bb567956c91",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 实际上 RequestChain，就是用了 HTTP Request Client 去请求了对应网站\n",
    "# 然后把对应网站的搜索结果，提交给 LLM 进行了一次汇总推理，像不像我们之前小墨的检索增强生成。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e569f415-190a-4b40-8414-78aa2c52870b",
   "metadata": {},
   "source": [
    "#### RetrievalQA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "ba18ca87-72f5-4785-b5e0-05c03ea08f6e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.vectorstores import Chroma\n",
    "from langchain.embeddings.openai import OpenAIEmbeddings\n",
    "\n",
    "embeddings = OpenAIEmbeddings()\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=1024,\n",
    ")\n",
    "\n",
    "texts = [\n",
    "    \"瑶瑶是墨问西东颜值担当\",\n",
    "    \"小盖是墨问西东最帅的男人\"\n",
    "]\n",
    "# 使用原始的数据，构建向量数据库\n",
    "docsearch = Chroma.from_texts(texts, embeddings)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "f7db6b8f-2a60-4836-9300-d7f989a37ddb",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Number of requested results 4 is greater than number of elements in index 2, updating n_results = 2\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'最帅的男人是小盖。'"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "\n",
    "qa = RetrievalQA.from_chain_type(llm=llm, chain_type=\"stuff\", retriever=docsearch.as_retriever())\n",
    "\n",
    "query = \"最帅的男人是谁\"\n",
    "qa.run(query)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4931d702-c114-4735-8c57-24ea4d71f591",
   "metadata": {},
   "source": [
    "#### SQLChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "9f2216fe-9892-4905-bbad-95b88aa9546a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如何我不想写任何代码去做CURD\n",
    "# 通过小墨自己去理解\n",
    "# 然后根据用户问题进行相关操作\n",
    "\n",
    "# 首先你的业务数据已经落库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "599bf3ef-22dd-4ff3-87c5-0c4399ebf581",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import SQLDatabase\n",
    "from langchain_experimental.sql import SQLDatabaseChain\n",
    "\n",
    "db = SQLDatabase.from_uri(\"mysql+pymysql://chatbot:Chatbot123@based-data-platfom.mysql.rds.aliyuncs.com/chatbot\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "0d2cde58-b1b9-4fa3-a123-dca30f5463ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "# insert into `employees` (`id`, `name`, `location` , `gender` , `phone` ) \n",
    " #values (1, 'Bill', 'Los Angeles', \"Male\", \"14081231111\"), \n",
    "#        (2, 'Steven', 'Chicago', \"Male\", \"14081232222\"), \n",
    "#        (3, 'Hayden', 'Los Angeles', \"Male\", \"14081233333\"), \n",
    "#        (4, 'Skyler', 'Washington', \"Male\", \"14081234444\"), \n",
    "#        (5, 'James', 'New York', \"Male\", \"14081235555\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "fb54738e-1963-459e-bc4c-763a384dd595",
   "metadata": {},
   "outputs": [],
   "source": [
    "db_chain = SQLDatabaseChain(llm=llm, database=db, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "8369435b-2c8c-46ea-8b99-00ac0fa7f89f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n",
      "How many employee are there?\n",
      "SQLQuery:\u001b[32;1m\u001b[1;3mSELECT COUNT(*) FROM employees\u001b[0m\n",
      "SQLResult: \u001b[33;1m\u001b[1;3m[(5,)]\u001b[0m\n",
      "Answer:\u001b[32;1m\u001b[1;3mThere are 5 employees.\u001b[0m\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'There are 5 employees.'"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "db_chain.run(\"How many employee are there?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "abb4f277-f910-4e9d-ab0e-80877b541045",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n",
      "What are the employee names?\n",
      "SQLQuery:\u001b[32;1m\u001b[1;3mSELECT `name` FROM `employees`\u001b[0m\n",
      "SQLResult: \u001b[33;1m\u001b[1;3m[('Bill',), ('Steven',), ('Hayden',), ('Skyler',), ('James',)]\u001b[0m\n",
      "Answer:\u001b[32;1m\u001b[1;3mBill, Steven, Hayden, Skyler, James\u001b[0m\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Bill, Steven, Hayden, Skyler, James'"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "db_chain.run(\"What are the employee names?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "943bf616-04fc-48d9-b6e5-7ea3d97ee30b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n",
      "How many employee live in LA?\n",
      "SQLQuery:\u001b[32;1m\u001b[1;3mSELECT COUNT(*) FROM employees WHERE location = 'Los Angeles'\u001b[0m\n",
      "SQLResult: \u001b[33;1m\u001b[1;3m[(2,)]\u001b[0m\n",
      "Answer:\u001b[32;1m\u001b[1;3m2\u001b[0m\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'2'"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "db_chain.run(\"How many employee live in LA?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "452be582-f57b-491d-a67a-8b65c4797ea5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n",
      "我的员工有多少是男性的？\n",
      "SQLQuery:\u001b[32;1m\u001b[1;3mSELECT COUNT(*) FROM employees WHERE gender = 'Male'\u001b[0m\n",
      "SQLResult: \u001b[33;1m\u001b[1;3m[(5,)]\u001b[0m\n",
      "Answer:\u001b[32;1m\u001b[1;3mFinal answer here: 我的员工有5个是男性的。\u001b[0m\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Final answer here: 我的员工有5个是男性的。'"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 中文一样也可以，取决于 LLM 的能力\n",
    "db_chain.run(\"我的员工有多少是男性的？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0350908c-f76a-4ed4-8626-fe6f01d1d417",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "06a376fe-ed2d-4585-b817-417eae296e7e",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "865e428c-a608-45c6-8ffb-e5c34387dbfa",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d27502c-f839-4e2f-9bce-a198fa4ec998",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "6c75413c-29f3-4f33-a92d-020e1933d98f",
   "metadata": {},
   "source": [
    "#### SimpleSequentialChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "aeeb3e72-89eb-41a0-bae0-92a0e51faa37",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 针对组合性任务\n",
    "# 例如 LLM 中文不好，英文缺很强\n",
    "# 能不能先把中文问题翻译成英文，用英文去提问，最终把结果转换成中文\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=1024,\n",
    ")\n",
    " \n",
    "translation_en_template = \"\"\"\n",
    "你是一名语言大师，请你将用户给定的文本进行翻译成英文。\n",
    "\n",
    "文本: {source_text}\n",
    "\"\"\"\n",
    "\n",
    "translation_en_prompt = PromptTemplate(\n",
    "    input_variables=['source_text'],\n",
    "    template=translation_en_template,\n",
    ")\n",
    "\n",
    "translation_en_chain=LLMChain(\n",
    "    llm=llm, \n",
    "    prompt=translation_en_prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "5cfa9f87-535d-4185-a731-ca2e9ec50c1a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'On Thanksgiving Day, what kind of food do Americans eat?'"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ask = \"在感恩节这一天，美国人会吃些什么食物\"\n",
    "result = translation_en_chain.run(source_text=ask)\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "id": "fab9c548-c46d-4be7-8856-53f6b0e2a656",
   "metadata": {},
   "outputs": [],
   "source": [
    "ask_template = \"\"\"\n",
    "{ask}\n",
    "\"\"\"\n",
    "\n",
    "ask_prompt = PromptTemplate(\n",
    "    input_variables=['ask'],\n",
    "    template=ask_template,\n",
    ")\n",
    "\n",
    "ask_chain=LLMChain(\n",
    "    llm=llm, \n",
    "    prompt=ask_prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "00921bb8-7620-4502-b7de-bf4cab16ee97",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'On Thanksgiving Day, Americans typically eat a variety of traditional foods. The centerpiece of the meal is usually a roasted turkey, which is often accompanied by stuffing or dressing, mashed potatoes, gravy, cranberry sauce, and green bean casserole. Other common dishes include sweet potatoes or yams, cornbread, dinner rolls, and a variety of vegetables. Desserts commonly enjoyed on Thanksgiving include pumpkin pie, apple pie, pecan pie, and various other sweet treats.'"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result = ask_chain.run(ask=result)\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "id": "6d7f10e1-ecb5-4140-93cb-003dea59b35f",
   "metadata": {},
   "outputs": [],
   "source": [
    "translation_zh_template = \"\"\"\n",
    "你是一名语言大师，请你将用户给定的文本进行翻译成中文。\n",
    "\n",
    "文本: {source_text}\n",
    "\"\"\"\n",
    "\n",
    "translation_zh_prompt = PromptTemplate(\n",
    "    input_variables=['source_text'],\n",
    "    template=translation_zh_template,\n",
    ")\n",
    "\n",
    "translation_zh_chain=LLMChain(\n",
    "    llm=llm, \n",
    "    prompt=translation_zh_prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "9814afa3-5f67-4b10-a331-f96307e0da68",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'在感恩节这一天，美国人通常会吃各种传统食物。餐桌上的主角通常是烤火鸡，常常搭配填料或调味料、土豆泥、肉汁、蔓越莓酱和绿豆烩菜。其他常见的菜肴包括红薯或山药、玉米面包、晚餐面包和各种蔬菜。感恩节上常享用的甜点包括南瓜派、苹果派、山核桃派和各种其他甜点。'"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "result = translation_zh_chain.run(source_text=result)\n",
    "result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "id": "5bc646c4-ff2a-48c3-a815-304d1fcb66b8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n",
      "\u001b[36;1m\u001b[1;3mOn Thanksgiving Day, what kind of food do Americans eat?\u001b[0m\n",
      "\u001b[33;1m\u001b[1;3mOn Thanksgiving Day, Americans typically eat a variety of traditional foods. The centerpiece of the meal is usually a roasted turkey, which is often accompanied by stuffing or dressing, mashed potatoes, gravy, cranberry sauce, and green bean casserole. Other common dishes include sweet potatoes or yams, cornbread, dinner rolls, and a variety of vegetables. Desserts commonly enjoyed on Thanksgiving include pumpkin pie, apple pie, pecan pie, and various other sweet treats.\u001b[0m\n",
      "\u001b[38;5;200m\u001b[1;3m在感恩节这一天，美国人通常会吃各种传统食物。餐桌上的主角通常是烤火鸡，常常搭配填料、土豆泥、肉汁、蔓越莓酱和绿豆烩菜。其他常见的菜肴包括红薯或山药、玉米面包、晚餐面包和各种蔬菜。感恩节上常享用的甜点包括南瓜派、苹果派、山核桃派和各种其他甜点。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'在感恩节这一天，美国人通常会吃各种传统食物。餐桌上的主角通常是烤火鸡，常常搭配填料、土豆泥、肉汁、蔓越莓酱和绿豆烩菜。其他常见的菜肴包括红薯或山药、玉米面包、晚餐面包和各种蔬菜。感恩节上常享用的甜点包括南瓜派、苹果派、山核桃派和各种其他甜点。'"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 只允许每一个 Chain 都只有一个 input_variables\n",
    "from langchain.chains import SimpleSequentialChain\n",
    "\n",
    "ss_chains = SimpleSequentialChain(chains=[translation_en_chain, ask_chain, translation_zh_chain], verbose=True)\n",
    "ss_chains.run(ask)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3684d94c-3217-4827-9405-1f712246df1c",
   "metadata": {},
   "source": [
    "#### SequentialChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "id": "587b1b06-8a49-4190-9540-216d4a326ebb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 让 Chain 支持多个 input_variables \n",
    "\n",
    "writer_template = \"\"\"\n",
    "你是一名小说作家，请你根据文章标题写出简介，要求在50字个字内。\\n文章标题: {title}\\n风格要求: {style}\n",
    "\"\"\"\n",
    "\n",
    "writer_prompt = PromptTemplate(\n",
    "    input_variables=['title', 'style'],\n",
    "    template=writer_template,\n",
    ")\n",
    "\n",
    "writer_chain=LLMChain(\n",
    "    llm=llm, \n",
    "    prompt=writer_prompt,\n",
    "    output_key=\"synopsis\",  # 需要特别注意，这个 output_key, 就是下一个 Chain 的 input_key,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "id": "309fb1fd-e857-4453-9b7b-bd43a37d8e86",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m\n",
      "你是一名小说作家，请你根据文章标题写出简介，要求在50字个字内。\n",
      "文章标题: 论中华不同地域的美食\n",
      "风格要求: 吸引人的\n",
      "\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'探索中华美食，品味地域独特的魅力。从北方的烤鸭到南方的海鲜，每一道菜都散发着浓郁的地域风味。让我们一起踏上美食之旅，领略中华烹饪的多样魅力！'"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "writer_chain.run(title=\"论中华不同地域的美食\", style=\"吸引人的\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "id": "4ed053a1-c1f0-4234-a75a-504eb3429040",
   "metadata": {},
   "outputs": [],
   "source": [
    "reviewer_template = \"\"\"\n",
    "你是一名文稿审核专家，请你根据用户输入的稿件进行审核，是否含有色情暴力政治等因素。\\n稿件简介: {synopsis}\n",
    "\"\"\"\n",
    "\n",
    "reviewer_prompt = PromptTemplate(\n",
    "    input_variables=['synopsis'],\n",
    "    template=reviewer_template,\n",
    ")\n",
    "\n",
    "reviewer_chain=LLMChain(\n",
    "    llm=llm, \n",
    "    prompt=reviewer_prompt,\n",
    "    verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "id": "a24699e4-0b6b-4b49-bc7c-80a22e27a00a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m\n",
      "你是一名文稿审核专家，请你根据用户输入的稿件进行审核，是否含有色情暴力政治等因素。\n",
      "稿件简介: 品味中国，尽览美食之珍！从北方的烤鸭到南方的粤菜，中华美食多样且令人垂涎欲滴。本文将带您领略中国各地独特的美食文化，让您的味蕾在这个多元的国度中尽情享受！\n",
      "\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'根据用户输入的稿件简介，该稿件不含有色情、暴力、政治等因素，可以通过审核。'"
      ]
     },
     "execution_count": 96,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reviewer_chain.run(synopsis=\"品味中国，尽览美食之珍！从北方的烤鸭到南方的粤菜，中华美食多样且令人垂涎欲滴。本文将带您领略中国各地独特的美食文化，让您的味蕾在这个多元的国度中尽情享受！\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "id": "14f2ecaf-1069-4082-ac08-8448e16ce97d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m\n",
      "你是一名小说作家，请你根据文章标题写出简介，要求在50字个字内。\n",
      "文章标题: 论中华不同地域的美食\n",
      "风格要求: 吸引人的\n",
      "\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m\n",
      "你是一名文稿审核专家，请你根据用户输入的稿件进行审核，是否含有色情暴力政治等因素。\n",
      "稿件简介: 探索中华美食，品味地域独特的魅力。从北方的烤鸭到南方的海鲜，每一道菜都散发着浓郁的地域风味。让我们一起踏上美食之旅，领略中华烹饪的多样魅力！\n",
      "\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'根据用户输入的稿件简介，我认为该稿件没有含有色情、暴力、政治等不良因素。它主要介绍了中华美食的地域特色和多样性，是一篇探索美食文化的正面内容。'"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.chains import SequentialChain\n",
    "\n",
    "s_chain = SequentialChain(\n",
    "    chains=[writer_chain, reviewer_chain], \n",
    "    input_variables=['title', 'style']\n",
    ")\n",
    "\n",
    "s_chain.run(title=\"论中华不同地域的美食\", style=\"吸引人的\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "id": "3b07ad39-1eba-4d52-834c-60d24961124c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如果是 SimpleSequentialChain, 直接报错\n",
    "# Chains used in SimplePipeline should all have one input, got verbose=True prompt=PromptTemplate(input_variables=['style', 'title']\n",
    "#\n",
    "# SimpleSequentialChain(\n",
    "#    chains=[writer_chain, reviewer_chain], \n",
    "#    input_variables=['title', 'style']\n",
    "# )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dd35e11b-7dd0-4a91-8bbf-0d3b2bbafc74",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 因为这里的 SimpleSequentialChain 报错会泄露 API Key，所以就不演示了"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c9a21d97-6809-4b0a-adfa-6b567d8c7860",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "de6ffd23-2e2a-426b-bc20-f5436de2b923",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a96c3d6-6800-44b5-9a9c-ae267b072b1e",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "8d3622ef-a377-447e-b069-be37f2938dc0",
   "metadata": {},
   "source": [
    "#### LLMRouterChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "id": "b6a835cf-3ed5-4577-a91e-87d9016e1afd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 把所有的能力抽象成工具，那如果要用工具的话怎么选择？\n",
    "# 那就需要有一个路由器角色来决定流量往哪里走\n",
    "# 类似我们要从北京去香港，可以选择坐高铁、自己开车、坐飞机...\n",
    "\n",
    "# 第一个工具\n",
    "math_template = \"你是一名数学老师，请你根据用户输入的数学问题计算结果后返回。数学问题: {input}\"\n",
    "\n",
    "# 第二个工具\n",
    "translation_template = \"你是一名翻译官，请将用户输入的文本翻译成英文。 原始文本: {input}\"\n",
    "\n",
    "prompt_infos = [\n",
    "    {\n",
    "        \"name\": \"math\",\n",
    "        \"description\": \"解答关于数学的所有问题\",\n",
    "        \"prompt_template\": math_template,\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"translator\",\n",
    "        \"description\": \"翻译用户的输入文本成指定语种\",\n",
    "        \"prompt_template\": translation_template,\n",
    "    }\n",
    "]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "id": "ccef7000-ba15-4a17-b24e-b72aee2e05b0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 根据 PromptTemplate 初始化 Chain，变成一个 destination_chains 集合（工具箱）\n",
    "destination_chains = {}\n",
    "for p_info in prompt_infos:\n",
    "    name = p_info[\"name\"]\n",
    "    prompt_template = p_info[\"prompt_template\"]\n",
    "    prompt = PromptTemplate(template=prompt_template, input_variables=[\"input\"])\n",
    "    chain = LLMChain(llm=llm, prompt=prompt)\n",
    "    destination_chains[name] = chain\n",
    "\n",
    "# 兜底的 Chain，以便在找不到合适的工具时使用\n",
    "default_chain = ConversationChain(llm=llm, output_key=\"text\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "a46e4542-0796-4310-adec-2be45832470e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 根据 Description 初始化 router_template， 再用 router_template 去初始化 router_chain（路由器）\n",
    "from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser\n",
    "from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE\n",
    "\n",
    "destinations = [f\"{p['name']}: {p['description']}\" for p in prompt_infos]\n",
    "destinations_str = \"\\n\".join(destinations)\n",
    "router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str)\n",
    "router_prompt = PromptTemplate(\n",
    "    template=router_template,\n",
    "    input_variables=[\"input\"],\n",
    "    output_parser=RouterOutputParser(),\n",
    ")\n",
    "router_chain = LLMRouterChain.from_llm(llm, router_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "id": "40857086-b457-4c2a-a71e-e3c1dd334730",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 有了路由器，有了目标工具，剩下就是把它俩打包一起，变成可执行的 Chain\n",
    "from langchain.chains.router import MultiPromptChain\n",
    "\n",
    "chain = MultiPromptChain(\n",
    "    router_chain=router_chain,\n",
    "    destination_chains=destination_chains,\n",
    "    default_chain=default_chain,\n",
    "    verbose=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "id": "7fd3035b-1d12-4779-a5ca-a5c51f1cf2ac",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n",
      "math: {'input': '258*963等于多少'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'258 * 963 = 248,454'"
      ]
     },
     "execution_count": 103,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 期望命中的是 math 这个 Chain\n",
    "chain.run(\"258*963等于多少\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "id": "6b4df9d7-2c3d-4eca-af5e-9539c449d6e0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n",
      "translator: {'input': '我和我的祖国，一刻也不能分割'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Me and my motherland, can never be separated even for a moment.'"
      ]
     },
     "execution_count": 104,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 期望命中的是 translation 这个 Chain\n",
    "chain.run(\"翻译: 我和我的祖国，一刻也不能分割\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "id": "182ec61f-6004-4bf5-9a0d-4d423e03cb8a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n",
      "None: {'input': '王菲的歌有什么'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'王菲是一位中国著名的女歌手，她的歌曲风格多样，涵盖了流行、摇滚、民谣等多种音乐类型。她的代表作品包括《传奇》、《红豆》、《匆匆那年》等。她的歌曲以其独特的嗓音和深情的演唱风格而受到广大听众的喜爱。'"
      ]
     },
     "execution_count": 105,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 期望命中兜底的 Chain\n",
    "chain.run(\"王菲的歌有什么\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ebb65251-cc83-4e8c-8766-d21ca5a92cf2",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a905837d-24db-4358-8642-389651af1765",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "91cc2384-f57c-4b9b-b5ac-ac4f8f44aa29",
   "metadata": {},
   "source": [
    "#### TransformChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "id": "d4cc1bff-6583-4243-aa45-1dcd46f07be8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 把 Hello world 替换成 Hello people\n",
    "# 这是方便一些任务与任务之间的处理\n",
    "# 类似也可以是接受一个长文本，然后只取前x段话，进行总结后输出\n",
    "def transform_func(data: dict) ->dict:\n",
    "    text_data: str = data[\"text\"]\n",
    "    file_content: str = text_data.replace(\"HelloWorld\", \"MapReduce\")\n",
    "    return {\"output_text\": file_content}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "id": "0b8e5219-6255-441b-a929-d790b768909e",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import TransformChain\n",
    "transform_chain = TransformChain(\n",
    "    input_variables=[\"text\"], output_variables=[\"output_text\"], transform=transform_func, verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "id": "83440e07-4699-4773-a46a-c8c39458029e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new TransformChain chain...\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'每一个学习大数据编程的人，可能都会从一个 MapReduce 的练习开始'"
      ]
     },
     "execution_count": 109,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "transform_chain.run(text=\"每一个学习大数据编程的人，可能都会从一个 HelloWorld 的练习开始\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5bff3ad9-e146-4c8b-9365-9374b74b5552",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b558e1e7-9c3c-4e3a-a6a4-60212ec03f33",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "edef2b47-bc7c-43c3-a2da-5568c8730b87",
   "metadata": {},
   "source": [
    "### LangChain Expression Language (LCEL)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "id": "69ff4874-d8db-4aed-99ed-1d440aa9d796",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.schema import StrOutputParser\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "prompt = ChatPromptTemplate.from_template(\"请简短的回答我，在{country}的法律中，未成年的定义是多少岁\")\n",
    "\n",
    "chain = prompt | llm | StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "id": "94d48359-70f6-4fd0-9697-5cd2ef36ba52",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'在日本的法律中，未成年的定义是20岁。'"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 与上次我们将 LangServe 的 API Path 是一样的，相辅相成\n",
    "chain.invoke({\"country\": \"日本\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "id": "a2dad553-f076-464c-9ebc-a1efb7b9f74a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始时间: 2023-10-30 02:50:55.846697\n",
      "['在日本的法律中，未成年的定义是20岁。', '在韩国的法律中，未成年的定义是19岁。', '在英国的法律中，未成年的定义是18岁以下。']\n",
      "结束时间: 2023-10-30 02:51:00.959140\n"
     ]
    }
   ],
   "source": [
    "# 请求并发数，一个一个来串行\n",
    "import datetime\n",
    "\n",
    "print(f'开始时间: {datetime.datetime.now()}')\n",
    "print(chain.batch([{\"country\": \"日本\"}, {\"country\": \"韩国\"}, {\"country\": \"英国\"}], config={\"max_concurrency\": 1}))\n",
    "print(f'结束时间: {datetime.datetime.now()}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "id": "694f803a-a43a-4798-a114-0789563bb35b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始时间: 2023-10-30 02:51:35.593436\n",
      "['在日本的法律中，未成年的定义是20岁。', '在韩国的法律中，未成年的定义是19岁。', '在英国的法律中，未成年的定义是18岁以下。']\n",
      "结束时间: 2023-10-30 02:51:38.247042\n"
     ]
    }
   ],
   "source": [
    "# 也可以全部一起去调用，并行\n",
    "\n",
    "print(f'开始时间: {datetime.datetime.now()}')\n",
    "print(chain.batch([{\"country\": \"日本\"}, {\"country\": \"韩国\"}, {\"country\": \"英国\"}], config={\"max_concurrency\": 5}))\n",
    "print(f'结束时间: {datetime.datetime.now()}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "id": "5bdb4dee-f9ef-4497-8ab6-7e0854d327ff",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "在日本，未成年的定义是20岁。\n",
      "\n",
      "在马来西亚，未成年的定义是18岁。\n",
      "\n",
      "在澳洲，未成年的定义在各个州和地区可能有所不同，通常是18岁或者16岁。"
     ]
    }
   ],
   "source": [
    "# 异步流式输出\n",
    "async for s in chain.astream({\"country\": \"日本、马来西亚、澳洲\"}):\n",
    "    print(s, end=\"\", flush=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "id": "a86d6bae-aceb-468a-8949-d442f1af7901",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'根据输入的信息，马来西亚的未成年定义是最低的，为18岁。'"
      ]
     },
     "execution_count": 117,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 与 SimpleSequentialChain 一样，可以把所有组件放一起表达\n",
    "\n",
    "query_prompt = ChatPromptTemplate.from_template(\"请简短的回答我，在{country}的法律中，未成年的定义是多少岁\")\n",
    "filter_prompt = ChatPromptTemplate.from_template(\"根据输入的信息，筛选出哪一个国家的未成年定义是最低的。相关信息: {info}\")\n",
    "\n",
    "chain = {\"info\": query_prompt | llm | StrOutputParser()} |  filter_prompt | llm  | StrOutputParser()\n",
    "\n",
    "chain.invoke({\"country\": \"日本、马来西亚、澳洲\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "id": "f6fd46b7-f16c-43be-b64b-bee1af747cff",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'info': '在日本，未成年的定义是20岁。\\n\\n在马来西亚，未成年的定义是18岁。\\n\\n在澳洲，未成年的定义在各个州和地区可能有所不同，通常是18岁或者16岁。',\n",
       " 'result': '根据输入的信息，马来西亚的未成年定义是最低的，为18岁。'}"
      ]
     },
     "execution_count": 120,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果需要获取中间结果，也可以通过这样的方式\n",
    "from langchain.schema.runnable import RunnablePassthrough\n",
    "\n",
    "query_chain = query_prompt | llm | StrOutputParser()\n",
    "filter_chain = filter_prompt | llm  | StrOutputParser()\n",
    "\n",
    "chain = {\"info\": query_chain} | RunnablePassthrough.assign(result=filter_chain)\n",
    "\n",
    "chain.invoke({\"country\": \"日本、马来西亚、澳洲\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "afed0fe3-1013-4c98-9fc9-d79650ef7c3e",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a0eef695-b8a1-4a3e-a6a6-e03336e2a7ff",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9238731d-bbb8-4ecf-bc96-1551b6668f81",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "061fe6cc-f347-4ec4-a726-c05c75ed82ac",
   "metadata": {},
   "source": [
    "## Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "id": "dafcdc26-9648-42a6-b1ed-4bd036a68ffe",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 好，以上的都是开胃小菜进行铺垫而已\n",
    "# \n",
    "# 这一节课，我们把小墨定义为是面向课程营销的机器人\n",
    "# 用于回答用户商品问题\n",
    "# 用于协助用户下单\n",
    "# 用于查询订单情况\n",
    "# ..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "id": "8409428d-51f9-4944-91e2-108cc508ee48",
   "metadata": {},
   "outputs": [],
   "source": [
    "#自治（Autonomy）：AI 虚拟智能体能够独立执行任务，而无需人工干预或输入。\n",
    "#知觉（Perception）：智能体功能通过各种传感器（如摄像头或麦克风）感知和解释它们所处的环境。\n",
    "#反应（Reactivity）：AI 智能体可以评估环境并做出相应的响应以实现其目标。\n",
    "#推理和决策（Reasoning and decision-making）：AI 智能体是智能工具，可以分析数据并做出决策以实现目标。他们使用推理技术和算法来处理信息并采取适当的行动。\n",
    "#学习（Learning）：可以通过机器、深度和强化学习元素和技术来学习和提高他们的表现。\n",
    "#通信（Communication）：AI 智能体可以使用不同的方法与其他智能体或人类进行通信，例如理解和响应自然语言、识别语音以及通过文本交换消息。\n",
    "#以目标为导向（Goal-oriented）：它们旨在实现特定目标，这些目标可以通过与环境的交互来预定义或学习。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0390a3ea-98a9-4c5d-affb-7385ffb61200",
   "metadata": {},
   "source": [
    "### Tools "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 125,
   "id": "ceb3c9ae-a577-41ac-8fb5-16314bde910c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.schema import AIMessage, HumanMessage, SystemMessage\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    model_name='gpt-3.5-turbo-0613',\n",
    "    temperature=0, max_tokens=2048,\n",
    ")\n",
    "\n",
    "def ChatCompletion(user_prompt):\n",
    "    messages = [\n",
    "        HumanMessage(content=user_prompt),\n",
    "    ]\n",
    "    return llm(messages).content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "id": "a2c0f0bd-35f2-4e66-b414-c785421f5bca",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_template = \"请回答 {name} 是什么时候出生的\"\n",
    "\n",
    "llm_chain = LLMChain(llm=llm, prompt=PromptTemplate.from_template(prompt_template))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "id": "c0ae5261-b9ee-45fb-892a-2877a811d698",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1+1=2'"
      ]
     },
     "execution_count": 127,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ChatCompletion(\"1+1=?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "id": "51927014-0e0e-4f26-b0de-da9463f6a332",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'赵雷是1992年8月12日出生的。'"
      ]
     },
     "execution_count": 128,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm_chain.run(name=\"赵雷\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "id": "ac36353c-aa71-42bb-b04f-9b6a280b88d4",
   "metadata": {},
   "outputs": [],
   "source": [
    "from tavily import Client\n",
    "tavily = Client(api_key=\"Replace to your API Key\")\n",
    "\n",
    "def search(query):\n",
    "    results = tavily.search(query=query, max_results=3)\n",
    "    \n",
    "    search_result = \"\"\n",
    "    for i, item in enumerate(results.get('results')):\n",
    "        search_result += f\"title: {item['title']}\\ncontent: {item['content']}\\n\\n\"\n",
    "        \n",
    "    return search_result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 130,
   "id": "26d1b7d8-426a-45cf-b811-d84d231321f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.tools import BaseTool, StructuredTool, Tool, tool\n",
    "\n",
    "tools = [\n",
    "    Tool.from_function(\n",
    "        func=llm_chain.run,\n",
    "        name=\"查询出生日期\",\n",
    "        description=\"可以帮助用户查询某个人的出生日期\"\n",
    "    )\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 131,
   "id": "2f79794c-f415-4ab9-bfba-83ec9442854a",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools.append(\n",
    "    Tool.from_function(\n",
    "        func=ChatCompletion,\n",
    "        name=\"通用查询\",\n",
    "        description=\"可以查询任何问题\"\n",
    "    ),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "id": "028177d3-5c04-4242-9daa-976eebc34459",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools.append(\n",
    "    Tool.from_function(\n",
    "        func=db_chain.run,\n",
    "        name=\"员工数据查询\",\n",
    "        description=\"可以查询有关员工的问题\"\n",
    "    ),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "id": "8fb8a86c-6fbd-4784-8c6b-54ff7be86213",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools.append(\n",
    "    Tool.from_function(\n",
    "        func=search,\n",
    "        name=\"搜索引擎实时查询\",\n",
    "        description=\"可以查询具有时效性的问题\"\n",
    "    ),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "id": "09edca37-2fa6-4cf7-91b1-101a8cb6a4d1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentType, initialize_agent\n",
    "\n",
    "agent = initialize_agent(\n",
    "    tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "id": "bd702d81-a4c8-4423-8e86-f5a557d97c2e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mI need to find out the birthdate of Zhang Xueyou.\n",
      "Action: 查询出生日期\n",
      "Action Input: 张学友\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m张学友出生于1961年9月10日。\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mI now know the final answer.\n",
      "Final Answer: 张学友出生于1961年9月10日。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'张学友出生于1961年9月10日。'"
      ]
     },
     "execution_count": 135,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent.run(\"我想查询下张学友是什么时候出生的\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "id": "340e4cf2-68bf-41bc-a3b4-932e610cb025",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mThis is a general knowledge question about fruits. I can use the general query tool to find the answer.\n",
      "Action: 通用查询\n",
      "Action Input: 苹果和榴莲都是热带水果吗\u001b[0m\n",
      "Observation: \u001b[33;1m\u001b[1;3m是的，苹果和榴莲都是热带水果。苹果是一种温带水果，但也可以在热带地区种植。榴莲则是一种热带水果，主要生长在热带地区，如东南亚国家。\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mI now know the final answer\n",
      "Final Answer: 是的，苹果和榴莲都是热带水果。苹果是一种温带水果，但也可以在热带地区种植。榴莲则是一种热带水果，主要生长在热带地区，如东南亚国家。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'是的，苹果和榴莲都是热带水果。苹果是一种温带水果，但也可以在热带地区种植。榴莲则是一种热带水果，主要生长在热带地区，如东南亚国家。'"
      ]
     },
     "execution_count": 137,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent.run(\"苹果和榴莲都是热带水果吗\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "id": "5a337793-3d3b-4d31-a903-c868692aab87",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mI need to find the ratio of male to female employees.\n",
      "Action: 员工数据查询\n",
      "Action Input: 查询员工性别比例\u001b[0m\n",
      "\n",
      "\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n",
      "查询员工性别比例\n",
      "SQLQuery:\u001b[32;1m\u001b[1;3mSELECT gender, COUNT(*) AS count FROM employees GROUP BY gender\u001b[0m\n",
      "SQLResult: \u001b[33;1m\u001b[1;3m[('Male', 5)]\u001b[0m\n",
      "Answer:\u001b[32;1m\u001b[1;3mThe gender ratio of the employees is 5:0, with all employees being male.\u001b[0m\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "Observation: \u001b[38;5;200m\u001b[1;3mThe gender ratio of the employees is 5:0, with all employees being male.\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mThe gender ratio of the employees is 5:0, with all employees being male.\n",
      "Final Answer: The ratio of male to female employees is 5:0.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'The ratio of male to female employees is 5:0.'"
      ]
     },
     "execution_count": 138,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent.run(\"我的员工男女的比率是多少\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "id": "35ff895c-264c-449b-865a-9a92cf16a4fb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mI need to find out what holiday falls on November 23, 2023 in the United States.\n",
      "Action: 查询出生日期\n",
      "Action Input: November 23, 2023\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mNovember 23, 2023 是一个日期，不是一个人的出生日期。\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mI need to use a different tool to find out what holiday falls on November 23, 2023 in the United States.\n",
      "Action: 搜索引擎实时查询\n",
      "Action Input: \"November 23, 2023 holiday in the United States\"\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mtitle: November 23 Holidays & National Days | 2023 Calendar\n",
      "content: November 23rd is the 327th day in the Gregorian calendar. On this day Yemeni President Ali Abdullah Saleh signed documents handing power to Yemen's Vice President after the Arab Spring protests; the first smartphone, the IBM Simon, was introduced at COMDEX in Las Vegas, and the Manchester Martyrs were hanged in Manchester, England after killing a police offer while freeing two Irish ...\n",
      "\n",
      "title: November 2023 Calendar with Holidays - United States\n",
      "content: + November 2023 Calendar with Holidays in printable format - United States. Includes 2023 Observances, Fun Facts & Religious Holidays: Christian, Catholic, Jewish & Muslim.\n",
      "\n",
      "title: November 23, 2023 Calendar with Holidays & Count Down - USA\n",
      "content: November 23, 2023 Popular Holidays & Observances Worldwide. Thanksgiving Day ( Día de Acción de Gracias) - Mexico, United States, Brazil, Puerto Rico. Rudolf Maister Day ( Dan Rudolfa Maistra) - Slovenia. Carers Rights Day - United Kingdom. Top Tweets on November 23rd 2023.\n",
      "\n",
      "\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mBased on the search results, November 23, 2023 is Thanksgiving Day in the United States.\n",
      "Final Answer: November 23, 2023 is Thanksgiving Day in the United States.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'November 23, 2023 is Thanksgiving Day in the United States.'"
      ]
     },
     "execution_count": 143,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent.run(\"2023年11月23号，是美国什么节日来的？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc023a49-5b67-49ec-89ff-7b7b8d9ff988",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "id": "ba335254-3364-4810-806a-6f26b43ac609",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 既然可以把一些能力抽象成工具\n",
    "# 那是否也可以抽象之前小墨的问答能力\n",
    "# 不仅仅对话，可以让小墨帮我们去做其他的操作\n",
    "# 而且在过程会自我规划，自我执行，自我反思"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d13b5c66-3497-4f00-99a7-65e4c74dd23a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "7fde5f30-84e8-4905-9861-7db1e346466e",
   "metadata": {},
   "source": [
    "## 工程化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "id": "59f2b5de-9ab4-4005-8b20-be4bceb1969a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 上代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ac4e85c7-5af9-4f89-a5ee-dad7fcc94f13",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b7d2b22-e028-4ac3-902a-b9abd28aa29d",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "2475995c-f044-4675-aff5-c4a9888dc778",
   "metadata": {},
   "source": [
    "## 总结和回顾"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fefa2b4d-747f-4705-89df-d5b00161f814",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e9df8ff-1baa-4bbc-bd86-f4b97cd58817",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f523862-1b36-43dc-9f1b-8f3f2ed1de51",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b623bdb6-dad7-4556-b4be-0725042ff149",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
